This script is very similar to degree_shifts_projected, but looks at 2˚ shifts instead of 1˚shifts.

Degree shifts

Second part of paper, if we move away from equator by 2˚ degree, how much habitat do we gain or lost

I need to look at shelf area by degrees latitude

library(raster)
library(sf)
library(ncdf4)
library(rmapshaper)
library(tidyverse)
library(diptest)
library(moments)
library(viridis) #colors
library(data.table)
library(hydroTSM) #hypsometric curves
library(gridExtra)
library(maptools)
library(rgdal)
library(rgeos)
library(SpaDES)
library(rnaturalearth)
library(rnaturalearthdata)


etopo_shelf_df <- readRDS("~/Documents/grad school/Rutgers/Repositories/shelf_habitat_distribution/etopo_shelf_df.rds")
#bring in bathymetry data frame for shelf regions

#LMEs
LME_spdf <- readOGR("LME66/LMEs66.shp") #spatial points data frame with all 66 LMEs
OGR data source with driver: ESRI Shapefile 
Source: "/Users/zoekitchel/Documents/grad school/Rutgers/Repositories/shelf_habitat_distribution/LME66/LMEs66.shp", layer: "LMEs66"
with 66 features
It has 9 fields
Integer64 fields read as strings:  OBJECTID 
#pull in shapefile for FAO statistical regions: 3/11/2021: http://www.fao.org/geonetwork/srv/en/main.home?uuid=ac02a460-da52-11dc-9d70-0017f293bd28
FAO_spdf <- readOGR("FAO_AREAS/FAO_AREAS.shp")
OGR data source with driver: ESRI Shapefile 
Source: "/Users/zoekitchel/Documents/grad school/Rutgers/Repositories/shelf_habitat_distribution/FAO_AREAS/FAO_AREAS.shp", layer: "FAO_AREAS"
with 324 features
It has 15 fields
#convert to equal area projection
#equalareaprojection<- crs(" +proj=eqearth ")

#The Lambert azimuthal equal-area projection is a particular mapping from a sphere to a disk. It accurately represents area in all regions of the sphere, but it does not accurately represent angles.
equalareaprojection<- crs(" +proj=laea ")

Make bathymetry data frame into raster (this takes a bit)

Note that I am trying to use the equal area projection


etopo_shelf_raster <- rasterFromXYZ(etopo_shelf_df, crs = crs(LME_spdf))

#reclassify all values <2000m in depth to 1 instead of actual depth
etopo_shelf_raster <- reclassify(etopo_shelf_raster,cbind(-Inf, Inf, 1))

Should go by projections of where species are moving: “Marine species (~80% being ectotherms in the database; Extended Data Fig. 2) have moved towards the poles at a mean (±s.e.m.) pace of 5.92 ± 0.94 km yr−1 (one-sample Student’s t-test: t=6.26; d.f. residuals=23; P=2.20×10–6), which is almost six times faster than terrestrial species (one-way analysis of variance (ANOVA): F=12.68; d.f. factor=1; d.f. residuals=45; P=8.88×10–4).” Lenoir 2020

5.92 km * 10 = 59.2 km in 10 years

59.2 km is how many degrees?

1° = 111 km, 2˚ = 222/59.2= 3.75, so roughly 35 years so,

222/59.2
[1] 3.75

0.5333˚ is representative of decadal shifts, but, for better visualization let’s go with 2˚ (representative of 40 year shifts)

I will put areas into 2˚ Bins (180 total degrees, so 180/2=90 total latitudinal bins)

180/2
[1] 90

How does continental shelf habitat change with latitude?

Look at contiguous coast lines.

I am going to leave out Antarctica (61) and the Arctic (64) as Antarctica drowned out patterns in lower latitudes and Arctic doesn’t have much habitat shallower than 2000m to begin with.

NB: For subarctic regions, I’m going by this figure where there appear to be splits between Europe and Greenland, Greenland and Canada, and Canada and Alaska. This is for sure up for discussion, but it seems like once species get above the continents, it is a big of a free for all.

Eastern Atlantic (3) -19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 58, 59, 60, 62

3/8 update (make more LMEs serve multiple coastlines, get rid of detached islands (New Zealand, Greenland, Iceland), and inner islands (aka Baltic Sea, mediterrraniean sea, red sea, black sea))

-20, 58, 57, 56, 21, 60, 22, 23* Baltic Sea, 24, 25, 27, 28, 29, 26 * Mediterranean, 62* Black Sea

Western Atlantic (2) - 5, 6, 7, 8, 9, 12, 14, 15, 16, 17, 18, 63, 66

-3/8 update, LEAVE OUT GREENLAND

Eastern Pacific (1) - 1, 2, 3, 4, 11, 13, 54, 55 **Beaufort sea thinly linked to Chukchi Sea, so split here, 65

-3/8 update -54, 1, 2, 53, 65, 3, 4** GOC, 11, 13

Western Indian (4) -30, 31, 32, 33

-3/8 update -30, 31, 33**black sea, 32

Eastern Indian (5) -34, 38, 43, 44, 45

-3/8 update -just use FAO statistical area 57

Western Pacific (6) 1, 35, 36, 37, 39, 40, 41, 42, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 57, 65

-3/8 update -42, 41, 50, 51, 52, 53, 1,54, 56, 57, 58, 20,and FAO statistical regions 71 and 61

Merge LMEs into 6 coastline regions

Masks for regions that are not included in LMEs (coordinates taken from Google maps). Will add in areas that do NOT overlap with existing LMEs at the end.

#Western Pacific, include FAO statistical regions 71 and 61
west_pac_fao <- FAO_spdf[FAO_spdf$F_CODE %in% c(61,71),]

#adjust extent a bit to get rid of rogue -178 points
west_pac_fao <- crop(west_pac_fao, extent(94, 180, -28.15, 66.4148))

west_pac_fao.raster <- crop(etopo_shelf_raster, extent(94, 180, -28.15, 66.4148))
west_pac_fao.raster <- mask(west_pac_fao.raster, west_pac_fao)

#Eastern Indian Ocean
east_ind_fao <- FAO_spdf[FAO_spdf$F_CODE == 57,]
west_pac <- c(42, 41, 50, 51, 52, 53, 1,54, 56, 57, 58, 20)
east_pac <- c(54, 1, 2, 53, 65, 3, 4, 11, 13)
west_atl <- c(66, 55, 63, 9, 8, 7, 6, 5, 12, 17, 16, 15, 14)
east_atl <- c(20, 58, 57, 56, 21, 60, 22, 23, 24, 25, 27, 28, 29, 26, 62)
west_ind <- c(30, 31, 33, 32)

#subregions based on LME_number
west_pac_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% west_pac,]
east_pac_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% east_pac,]
west_atl_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% west_atl,]
west_ind_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% west_ind,]
east_atl_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% east_atl,]
east_ind_spdf <- east_ind_fao

#for subregions that span 360, we need to change CRS a bit
newCRS_west <- "+proj=longlat +datum=WGS84 +lon_wrap=180" #this shifts 180 degrees
west_pac_spdf_shift <- spTransform(west_pac_spdf, CRS(newCRS_west))
west_pac_spdf_shift <- gBuffer(west_pac_spdf_shift, byid=TRUE, width=0) #gets rid of buffers, allows for union
Spatial object is not projected; GEOS expects planar coordinates
newCRS_east <- "+proj=longlat +datum=WGS84 +lon_wrap=180" #this shifts 180 degrees
east_pac_spdf_shift <- spTransform(east_pac_spdf, CRS(newCRS_east))
east_pac_spdf_shift <- gBuffer(east_pac_spdf_shift, byid=TRUE, width=0) #gets rid of buffers, allows for union
Spatial object is not projected; GEOS expects planar coordinates
#rotate raster for bathymetry (guided by extent of etoposhelf raster,  that's why wacky #s)
x1 <- crop(etopo_shelf_raster, extent(-180.0167, -0.0167, -90.01667, 90.01667))
x2 <- crop(etopo_shelf_raster, extent(0, 180.0167, -90.01667, 90.01667))   
extent(x1) <- c(180.0167, 360.0167, -90.01667 , 90.01667)
etopo_shelf_raster_180 <- merge(x1, x2)

#get rid of buffer for east atl as well to allow for union

east_atl_spdf_nobuf <- gBuffer(east_atl_spdf, byid=TRUE, width=0)
Spatial object is not projected; GEOS expects planar coordinates
region_names <- c("west_pac_spdf_shift", "east_pac_spdf_shift", "west_atl_spdf", "west_ind_spdf", "east_atl_spdf_nobuf", "east_ind_spdf")



#dissolve all polygons by region
for (i in 1:length(region_names)) {
  name <- paste0(region_names[i], "_agg")
  assign(name, gUnaryUnion(get(region_names[i]))) #dissolve polygons within coastline region into one
}

Extract bathymetry data from polygon only to make sure we’re limiting to shelf regions above 2000 meters


region_names_shift <- region_names[1:2]


region_names_noshift <- region_names[3:6]


for (i in 1:length(region_names_noshift)) {
#crop bathymetry layer to LME subset (continental shelf habitat in LMEs)
  raster_extent <-
       crop(etopo_shelf_raster, extent(get(paste0(region_names_noshift[i], "_agg"))))

#which areas of raster fall within borders?
  assign(paste0(region_names_noshift[i], "_mask"),
       mask(raster_extent, get(paste0(region_names_noshift[i], "_agg"))))
  
    assign(paste0(region_names_noshift[i], "_mask_1s"),
       reclassify(get(paste0(region_names_noshift[i], "_mask")), cbind(-Inf, Inf, 1)))

  

}

#edit for east_pac_spdf_shift and west_pac_spdf_shift (+180˚)

for (i in 1:length(region_names_shift[1:2])) {
#crop bathy layer to LME subset
  raster_extent <-
       crop(etopo_shelf_raster_180, extent(get(paste0(region_names_shift[i], "_agg"))))

#which areas of raster fall within borders?
  assign(paste0(region_names_shift[i], "_mask"),
       mask(raster_extent, get(paste0(region_names_shift[i], "_agg"))))
  
    assign(paste0(region_names_shift[i], "_mask_1s"),
       reclassify(get(paste0(region_names_shift[i], "_mask")), cbind(-Inf, Inf, 1)))

}

Merge in areas unaccounted for by LMEs (Philippines, Sumatra, Papua New Guinea)

#western pacific ocean
west_pac_spdf_mask_full <- merge(west_pac_fao.raster, west_pac_spdf_shift_mask_1s)

How to calculate area?

Now, we will split each coastline raster into latitudinal bins of 2˚

If these have already been done, load in from file instead of recreating because that takes some time.

load("west_pac_shelf_areas_2degrees.Rdata")
load("west_atl_shelf_areas_2degrees.Rdata")
load("west_ind_shelf_areas_2degrees.Rdata")
load("east_pac_shelf_areas_2degrees.Rdata")
load("east_atl_shelf_areas_2degrees.Rdata")
load("east_ind_shelf_areas_2degrees.Rdata")

Western Pacific

north_extent <- c(xmin(west_pac_spdf_mask_full), xmax(west_pac_spdf_mask_full), 0, ymax(west_pac_spdf_mask_full))
south_extent <- c(xmin(west_pac_spdf_mask_full), xmax(west_pac_spdf_mask_full), ymin(west_pac_spdf_mask_full), 0)

#crop west_pac raster above and below 0
west_pac_spdf_shift_agg_north <- crop(west_pac_spdf_mask_full, extent(north_extent))

west_pac_spdf_shift_agg_south <- crop(west_pac_spdf_mask_full, extent(south_extent))

#unfortunately, I think I may have to just do this manually (ugly, I know)

#all chunks for west pacific
west_pac_north_latitudes <- seq(0, ymax(west_pac_spdf_mask_full), by = 2)
west_pac_south_latitudes <- seq(0, ymin(west_pac_spdf_mask_full), by = -2)

#setup data table to populate in loop, subtracting one to allow for bins
west_pac_shelf_areas <- as.data.table(matrix(nrow = (length(west_pac_north_latitudes)-1+length(west_pac_south_latitudes)-1)))
                                      
west_pac_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]

#loop for north
for (i in 1:(length(west_pac_north_latitudes)-1)) {
  #setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
  north_extent <- c(xmin(west_pac_spdf_mask_full), xmax(west_pac_spdf_mask_full), west_pac_north_latitudes[i], west_pac_north_latitudes[i+1])
  
  #crop raster segement based on bin extent
  segment_north <- crop(west_pac_spdf_mask_full, extent(north_extent))
  
  #populate data table with latitudinal bin
  west_pac_shelf_areas[i, "latitude_start"] <- west_pac_north_latitudes[i]
  west_pac_shelf_areas[i, "latitude_end"] <- west_pac_north_latitudes[i+1]
  
  if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
    
  west_pac_shelf_areas[i, "area_equalareaproj"] <- 0
  west_pac_shelf_areas[i, "area_rasterarea"] <- 0
  west_pac_shelf_areas[i, "area_rgeos_gArea"] <- 0

  
  print(i)
    
  } else { #if there is shelf area within the bin, calculate area of slice
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_north)]
    
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
    
  #populate data table with raster area
  west_pac_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
    
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_north.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with polygon area using raster calculation
  west_pac_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
  
  #populate data table with polygon area using regeos calculation
  west_pac_shelf_areas[i, "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
[1] 40
[1] 41
#loop for south
for (i in 1:(length(west_pac_south_latitudes)-1)) {
  south_extent <- c(xmin(west_pac_spdf_mask_full), xmax(west_pac_spdf_mask_full), west_pac_south_latitudes[i+1], west_pac_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
  
  #raster segment
  segment_south <- crop(west_pac_spdf_mask_full, extent(south_extent))
  
  #add latitude bin info to data table
    west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "latitude_start"] <- west_pac_south_latitudes[i]
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "latitude_end"] <- west_pac_south_latitudes[i+1]
  
  
  if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude
    
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_equalareaproj"] <- 0
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rasterarea"] <- 0
    west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rgeos_gArea"] <- 0
  
  print(i)
    
  } else {
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_south)]
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
    
  #populate data table with raster area
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
    
  
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_south.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with area of polygon from raster::area function
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
  
  #populate data table from rgeos area calculation for projected polygon
  west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons

ggplot(data = west_pac_shelf_areas) +
  geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
  labs(x=paste0("Latitude ","\u00B0","E"), y = "Area km^2") +
  theme_classic()


cor(west_pac_shelf_areas[,3:5], use = "complete.obs")
                   area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea          1.0000000          0.9999895        0.9999895
area_equalareaproj       0.9999895          1.0000000        1.0000000
area_rgeos_gArea         0.9999895          1.0000000        1.0000000
save(west_pac_shelf_areas, file = "west_pac_shelf_areas_2degrees.Rdata")
load("west_pac_shelf_areas_2degrees.Rdata")

Classify by percent change!!

between 1 and Inf % change = at least 2 fold increase (note I classified any change from 0 to something as NOT a significant change, should return to this conceptually)

between -0.5 and -inf % change = at least 2 fold decrease

between -0.499 and 0.999 = no significant change

For area metric here, I used the raster::area function applied to the projected shapefile

west_pac_shelf_areas[, percent_change := (area_rasterarea-data.table::shift(area_rasterarea, type = "lag"))/data.table::shift(area_rasterarea, type = "lag")][,area_1000s := area_rasterarea/1000]

west_pac_shelf_areas[,hemisphere := ifelse(latitude_end>0,"north","south")]

west_pac_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

west_pac_shelf_areas_highlight <- west_pac_shelf_areas[change_above_2fold != 0,]

west_pac_shelf_areas_stats <- table(west_pac_shelf_areas[,.(change_above_2fold,hemisphere)])

Model change for southern and northern hemisphere

#add mid latitude
west_pac_shelf_areas[,latitude_mid := abs((latitude_end+latitude_start)/2)]

west_pac_north_mod <- lm(data = west_pac_shelf_areas[hemisphere == "north"], area_rasterarea ~ latitude_mid)
summary(west_pac_north_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = west_pac_shelf_areas[hemisphere == 
    "north"])

Residuals:
    Min      1Q  Median      3Q     Max 
-271843 -127822  -48263   92044  575518 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)   
(Intercept)     50714      62445   0.812  0.42165   
latitude_mid     4378       1319   3.319  0.00196 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 199900 on 39 degrees of freedom
Multiple R-squared:  0.2203,    Adjusted R-squared:  0.2003 
F-statistic: 11.02 on 1 and 39 DF,  p-value: 0.001965
west_pac_south_mod <- lm(data = west_pac_shelf_areas[hemisphere == "south"], area_rasterarea ~ latitude_mid)
summary(west_pac_south_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = west_pac_shelf_areas[hemisphere == 
    "south"])

Residuals:
   Min     1Q Median     3Q    Max 
-76592 -57214 -20806  45458 147715 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)    272341      29745   9.156 8.87e-09 ***
latitude_mid    -6999       1120  -6.247 3.39e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 71280 on 21 degrees of freedom
Multiple R-squared:  0.6502,    Adjusted R-squared:  0.6335 
F-statistic: 39.03 on 1 and 21 DF,  p-value: 3.388e-06

Eastern Pacific

east_pac_spdf_shift

north_extent <- c(xmin(east_pac_spdf_shift_mask_1s), xmax(east_pac_spdf_shift_mask_1s), 0, ymax(east_pac_spdf_shift_mask_1s))
south_extent <- c(xmin(east_pac_spdf_shift_mask_1s), xmax(east_pac_spdf_shift_mask_1s), ymin(east_pac_spdf_shift_mask_1s), 0)

#crop east_pac raster above and below 0
east_pac_spdf_shift_agg_north <- crop(east_pac_spdf_shift_mask_1s, extent(north_extent))

east_pac_spdf_shift_agg_south <- crop(east_pac_spdf_shift_mask_1s, extent(south_extent))

#unfortunately, I think I may have to just do this manually (ugly, I know)

#all chunks for east pacific
east_pac_north_latitudes <- seq(0, ymax(east_pac_spdf_shift_mask_1s), by = 2)
east_pac_south_latitudes <- seq(0, ymin(east_pac_spdf_shift_mask_1s), by = -2)

#setup data table to populate in loop, subtracting one to allow for bins
east_pac_shelf_areas <- as.data.table(matrix(nrow = (length(east_pac_north_latitudes)-1+length(east_pac_south_latitudes)-1)))
                                      
east_pac_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]

#loop for north
for (i in 1:(length(east_pac_north_latitudes)-1)) {
  #setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
  north_extent <- c(xmin(east_pac_spdf_shift_mask_1s), xmax(east_pac_spdf_shift_mask_1s), east_pac_north_latitudes[i], east_pac_north_latitudes[i+1])
  
  #crop raster segement based on bin extent
  segment_north <- crop(east_pac_spdf_shift_mask_1s, extent(north_extent))
  
  #populate data table with latitudinal bin
  east_pac_shelf_areas[i, "latitude_start"] <- east_pac_north_latitudes[i]
  east_pac_shelf_areas[i, "latitude_end"] <- east_pac_north_latitudes[i+1]
  
  if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
    
  east_pac_shelf_areas[i, "area_equalareaproj"] <- 0
  east_pac_shelf_areas[i, "area_rasterarea"] <- 0
  east_pac_shelf_areas[i, "area_rgeos_gArea"] <- 0

  
  print(i)
    
  } else { #if there is shelf area within the bin, calculate area of slice
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_north)]
    
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
    
  #populate data table with raster area
  east_pac_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
    
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_north.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with polygon area using raster calculation
  east_pac_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
  
  #populate data table with polygon area using regeos calculation
  east_pac_shelf_areas[i, "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
#loop for south
for (i in 1:(length(east_pac_south_latitudes)-1)) {
  south_extent <- c(xmin(east_pac_spdf_shift_mask_1s), xmax(east_pac_spdf_shift_mask_1s), east_pac_south_latitudes[i+1], east_pac_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
  
  #raster segment
  segment_south <- crop(east_pac_spdf_shift_mask_1s, extent(south_extent))
  
  #add latitude bin info to data table
    east_pac_shelf_areas[i+(length(east_pac_north_latitudes)-1), "latitude_start"] <- east_pac_south_latitudes[i]
  east_pac_shelf_areas[i+(length(east_pac_north_latitudes)-1), "latitude_end"] <- east_pac_south_latitudes[i+1]
  
  
  if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude

  east_pac_shelf_areas[i+(length(east_pac_north_latitudes)-1), "area_equalareaproj"] <- 0
  east_pac_shelf_areas[i+(length(east_pac_north_latitudes)-1), "area_rasterarea"] <- 0
    east_pac_shelf_areas[i+(length(east_pac_north_latitudes)-1), "area_rgeos_gArea"] <- 0
  
  print(i)
    
  } else {
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_south)]
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
    
  #populate data table with raster area
  east_pac_shelf_areas[i+(length(east_pac_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
    
  
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_south.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with area of polygon from raster::area function
  east_pac_shelf_areas[i+(length(east_pac_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
  
  #populate data table from rgeos area calculation for projected polygon
  east_pac_shelf_areas[i+(length(east_pac_north_latitudes)-1), "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons

ggplot(data = east_pac_shelf_areas) +
  geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
  labs(x=paste0("Latitude ","\u00B0","E"), y = "Area km^2") +
  theme_classic()


cor(east_pac_shelf_areas[,3:5], use = "complete.obs")
                   area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea          1.0000000          0.9999981        0.9999981
area_equalareaproj       0.9999981          1.0000000        1.0000000
area_rgeos_gArea         0.9999981          1.0000000        1.0000000
save(east_pac_shelf_areas, file = "east_pac_shelf_areas_2degrees.Rdata")
east_pac_shelf_areas[, percent_change := (area_rasterarea-data.table::shift(area_rasterarea, type = "lag"))/data.table::shift(area_rasterarea, type = "lag")][,area_1000s := area_rasterarea/1000]

east_pac_shelf_areas[,hemisphere := ifelse(latitude_end>0,"north","south")]

east_pac_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

east_pac_shelf_areas_highlight <- east_pac_shelf_areas[change_above_2fold != 0,]

east_pac_shelf_areas_stats <- table(east_pac_shelf_areas[,.(change_above_2fold, hemisphere)])

Model change for southern and northern hemisphere

#add mid latitude
east_pac_shelf_areas[,latitude_mid := abs((latitude_end+latitude_start)/2)]

east_pac_north_mod <- lm(data = east_pac_shelf_areas[hemisphere == "north"], area_rasterarea ~ latitude_mid)
summary(east_pac_north_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = east_pac_shelf_areas[hemisphere == 
    "north"])

Residuals:
    Min      1Q  Median      3Q     Max 
-149534  -48705  -12794   29647  236105 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -26354.6    22136.0  -1.191    0.241    
latitude_mid   2330.7      491.6   4.741 3.13e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 69100 on 37 degrees of freedom
Multiple R-squared:  0.3779,    Adjusted R-squared:  0.3611 
F-statistic: 22.48 on 1 and 37 DF,  p-value: 3.129e-05
east_pac_south_mod <- lm(data = east_pac_shelf_areas[hemisphere == "south"], area_rasterarea ~ latitude_mid)
summary(east_pac_south_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = east_pac_shelf_areas[hemisphere == 
    "south"])

Residuals:
   Min     1Q Median     3Q    Max 
 -9387  -6276  -1971   4510  19683 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)    5787.0     3139.0   1.844   0.0767 .
latitude_mid    133.6       97.1   1.376   0.1805  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 8301 on 26 degrees of freedom
Multiple R-squared:  0.06789,   Adjusted R-squared:  0.03204 
F-statistic: 1.894 on 1 and 26 DF,  p-value: 0.1805

Western Atlantic

west_atl_spdf_mask

north_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), 0, ymax(west_atl_spdf_mask_1s))
south_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), ymin(west_atl_spdf_mask_1s), 0)

#crop west_atl raster above and below 0
west_atl_spdf_shift_agg_north <- crop(west_atl_spdf_mask_1s, extent(north_extent))

west_atl_spdf_shift_agg_south <- crop(west_atl_spdf_mask_1s, extent(south_extent))

#unfortunately, I think I may have to just do this manually (ugly, I know)

#all chunks for west atlantic
west_atl_north_latitudes <- seq(0, ymax(west_atl_spdf_mask_1s), by = 2)
west_atl_south_latitudes <- seq(0, ymin(west_atl_spdf_mask_1s), by = -2)

#setup data table to populate in loop, subtracting one to allow for bins
west_atl_shelf_areas <- as.data.table(matrix(nrow = (length(west_atl_north_latitudes)-1+length(west_atl_south_latitudes)-1)))
                                      
west_atl_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]

#loop for north
for (i in 1:(length(west_atl_north_latitudes)-1)) {
  #setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
  north_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), west_atl_north_latitudes[i], west_atl_north_latitudes[i+1])
  
  #crop raster segement based on bin extent
  segment_north <- crop(west_atl_spdf_mask_1s, extent(north_extent))
  
  #populate data table with latitudinal bin
  west_atl_shelf_areas[i, "latitude_start"] <- west_atl_north_latitudes[i]
  west_atl_shelf_areas[i, "latitude_end"] <- west_atl_north_latitudes[i+1]
  
  if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
    
  west_atl_shelf_areas[i, "area_equalareaproj"] <- 0
  west_atl_shelf_areas[i, "area_rasterarea"] <- 0
  west_atl_shelf_areas[i, "area_rgeos_gArea"] <- 0

  print(i)
    
  } else { #if there is shelf area within the bin, calculate area of slice
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_north)]
    
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
    
  #populate data table with raster area
  west_atl_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
    
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_north.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with polygon area using raster calculation
  west_atl_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
  
  #populate data table with polygon area using regeos calculation
  west_atl_shelf_areas[i, "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
[1] 40
[1] 41
[1] 42
#loop for south
for (i in 1:(length(west_atl_south_latitudes)-1)) {
  south_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), west_atl_south_latitudes[i+1], west_atl_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
  
  #raster segment
  segment_south <- crop(west_atl_spdf_mask_1s, extent(south_extent))
  
  #add latitude bin info to data table
    west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "latitude_start"] <- west_atl_south_latitudes[i]
  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "latitude_end"] <- west_atl_south_latitudes[i+1]
  
  
  if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude

  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_equalareaproj"] <- 0
  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rasterarea"] <- 0
    west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rgeos_gArea"] <- 0
  
  print(i)
    
  } else {
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_south)]
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
    
  #populate data table with raster area
  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
    
  
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_south.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with area of polygon from raster::area function
  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
  
  #populate data table from rgeos area calculation for projected polygon
  west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons

ggplot(data = west_atl_shelf_areas) +
  geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
  labs(x=paste0("Latitude ","\u00B0","E"), y = "Area km^2") +
  theme_classic()


cor(west_atl_shelf_areas[,3:5], use = "complete.obs")
                   area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea          1.0000000          0.9999826        0.9999826
area_equalareaproj       0.9999826          1.0000000        1.0000000
area_rgeos_gArea         0.9999826          1.0000000        1.0000000
west_atl_shelf_areas[, percent_change := (area_rasterarea-data.table::shift(area_rasterarea, type = "lag"))/data.table::shift(area_rasterarea, type = "lag")][,area_1000s := area_rasterarea/1000]

west_atl_shelf_areas[,hemisphere := ifelse(latitude_end>0,"north","south")]

west_atl_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

west_atl_shelf_areas_highlight <- west_atl_shelf_areas[change_above_2fold != 0,]

west_atl_shelf_areas_stats <- table(west_atl_shelf_areas[,.(change_above_2fold, hemisphere)])

Model change for southern and northern hemisphere

#add mid latitude
west_atl_shelf_areas[,latitude_mid := abs((latitude_end+latitude_start)/2)]

west_atl_north_mod <- lm(data = west_atl_shelf_areas[hemisphere == "north"], area_rasterarea ~ latitude_mid)
summary(west_atl_north_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = west_atl_shelf_areas[hemisphere == 
    "north"])

Residuals:
   Min     1Q Median     3Q    Max 
-86017 -41622 -11628  38179 142471 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   72483.7    18917.6   3.832  0.00044 ***
latitude_mid   1134.8      390.1   2.909  0.00589 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 61290 on 40 degrees of freedom
Multiple R-squared:  0.1746,    Adjusted R-squared:  0.154 
F-statistic: 8.463 on 1 and 40 DF,  p-value: 0.005892
west_atl_south_mod <- lm(data = west_atl_shelf_areas[hemisphere == "south"], area_rasterarea ~ latitude_mid)
summary(west_atl_south_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = west_atl_shelf_areas[hemisphere == 
    "south"])

Residuals:
   Min     1Q Median     3Q    Max 
-27966 -21419  -1867   8729  71107 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)    2423.7    10229.5   0.237    0.815    
latitude_mid   1973.7      328.2   6.014 2.78e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 26560 on 25 degrees of freedom
Multiple R-squared:  0.5913,    Adjusted R-squared:  0.575 
F-statistic: 36.17 on 1 and 25 DF,  p-value: 2.783e-06

Eastern Atlantic

east_atl_spdf_nobuf_mask

north_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), 0, ymax(east_atl_spdf_nobuf_mask_1s))
south_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), ymin(east_atl_spdf_nobuf_mask_1s), 0)

#crop east_atl raster above and below 0
east_atl_spdf_shift_agg_north <- crop(east_atl_spdf_nobuf_mask_1s, extent(north_extent))

east_atl_spdf_shift_agg_south <- crop(east_atl_spdf_nobuf_mask_1s, extent(south_extent))

#unfortunately, I think I may have to just do this manually (ugly, I know)

#all chunks for east atlantic
east_atl_north_latitudes <- seq(0, ymax(east_atl_spdf_nobuf_mask_1s), by = 2)
east_atl_south_latitudes <- seq(0, ymin(east_atl_spdf_nobuf_mask_1s), by = -2)

#setup data table to populate in loop, subtracting one to allow for bins
east_atl_shelf_areas <- as.data.table(matrix(nrow = (length(east_atl_north_latitudes)-1+length(east_atl_south_latitudes)-1)))
                                      
east_atl_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]

#loop for north
for (i in 1:(length(east_atl_north_latitudes)-1)) {
  #setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
  north_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), east_atl_north_latitudes[i], east_atl_north_latitudes[i+1])
  
  #crop raster segement based on bin extent
  segment_north <- crop(east_atl_spdf_nobuf_mask_1s, extent(north_extent))
  
  #populate data table with latitudinal bin
  east_atl_shelf_areas[i, "latitude_start"] <- east_atl_north_latitudes[i]
  east_atl_shelf_areas[i, "latitude_end"] <- east_atl_north_latitudes[i+1]
  
  if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
    
  east_atl_shelf_areas[i, "area_equalareaproj"] <- 0
  east_atl_shelf_areas[i, "area_rasterarea"] <- 0
  east_atl_shelf_areas[i, "area_rgeos_gArea"] <- 0

  
  print(i)
    
  } else { #if there is shelf area within the bin, calculate area of slice
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_north)]
    
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
    
  #populate data table with raster area
  east_atl_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
    
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_north.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with polygon area using raster calculation
  east_atl_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
  
  #populate data table with polygon area using regeos calculation
  east_atl_shelf_areas[i, "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
[1] 40
[1] 41
#loop for south
for (i in 1:(length(east_atl_south_latitudes)-1)) {
  south_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), east_atl_south_latitudes[i+1], east_atl_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
  
  #raster segment
  segment_south <- crop(east_atl_spdf_nobuf_mask_1s, extent(south_extent))
  
  #add latitude bin info to data table
    east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "latitude_start"] <- east_atl_south_latitudes[i]
  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "latitude_end"] <- east_atl_south_latitudes[i+1]
  
  
  if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude

  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_equalareaproj"] <- 0
  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rasterarea"] <- 0
    east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rgeos_gArea"] <- 0
  
  print(i)
    
  } else {
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_south)]
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
    
  #populate data table with raster area
  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
    
  
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_south.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with area of polygon from raster::area function
  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
  
  #populate data table from rgeos area calculation for projected polygon
  east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons

ggplot(data = east_atl_shelf_areas) +
  geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
  labs(x=paste0("Latitude ","\u00B0","E"), y = "Area km^2") +
  theme_classic()


cor(east_atl_shelf_areas[,3:5], use = "complete.obs")
                   area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea          1.0000000          0.9999984        0.9999984
area_equalareaproj       0.9999984          1.0000000        1.0000000
area_rgeos_gArea         0.9999984          1.0000000        1.0000000
east_atl_shelf_areas[, percent_change := (area_rasterarea-data.table::shift(area_rasterarea, type = "lag"))/data.table::shift(area_rasterarea, type = "lag")][,area_1000s := area_rasterarea/1000]

east_atl_shelf_areas[,hemisphere := ifelse(latitude_end>0,"north","south")]

east_atl_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

east_atl_shelf_areas_highlight <- east_atl_shelf_areas[change_above_2fold != 0,]

east_atl_shelf_areas_stats <- table(east_atl_shelf_areas[,.(change_above_2fold, hemisphere)])

Model change for southern and northern hemisphere

#add mid latitude
east_atl_shelf_areas[,latitude_mid := abs((latitude_end+latitude_start)/2)]

east_atl_north_mod <- lm(data = east_atl_shelf_areas[hemisphere == "north"], area_rasterarea ~ latitude_mid)
summary(east_atl_north_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = east_atl_shelf_areas[hemisphere == 
    "north"])

Residuals:
    Min      1Q  Median      3Q     Max 
-232911  -81720  -36339   78443  406088 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -102304.8    46235.0  -2.213   0.0328 *  
latitude_mid    6586.0      976.7   6.743 4.83e-08 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 148000 on 39 degrees of freedom
Multiple R-squared:  0.5383,    Adjusted R-squared:  0.5265 
F-statistic: 45.47 on 1 and 39 DF,  p-value: 4.833e-08
east_atl_south_mod <- lm(data = east_atl_shelf_areas[hemisphere == "south"], area_rasterarea ~ latitude_mid)
summary(east_atl_south_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = east_atl_shelf_areas[hemisphere == 
    "south"])

Residuals:
   Min     1Q Median     3Q    Max 
-14704  -6419   1874   5828  16485 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)    7823.1     4568.4   1.712    0.106  
latitude_mid    614.7      219.9   2.796    0.013 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 9680 on 16 degrees of freedom
Multiple R-squared:  0.3282,    Adjusted R-squared:  0.2862 
F-statistic: 7.815 on 1 and 16 DF,  p-value: 0.01296

Western Indian

west_ind_spdf_mask

north_extent <- c(xmin(west_ind_spdf_mask_1s), xmax(west_ind_spdf_mask_1s), 0, ymax(west_ind_spdf_mask_1s))
south_extent <- c(xmin(west_ind_spdf_mask_1s), xmax(west_ind_spdf_mask_1s), ymin(west_ind_spdf_mask_1s), 0)

#crop west_ind raster above and below 0
west_ind_spdf_shift_agg_north <- crop(west_ind_spdf_mask_1s, extent(north_extent))

west_ind_spdf_shift_agg_south <- crop(west_ind_spdf_mask_1s, extent(south_extent))

#unfortunately, I think I may have to just do this manually (ugly, I know)

#all chunks for west indian
west_ind_north_latitudes <- seq(0, ymax(west_ind_spdf_mask_1s), by = 2)
west_ind_south_latitudes <- seq(0, ymin(west_ind_spdf_mask_1s), by = -2)

#setup data table to populate in loop, subtracting one to allow for bins
west_ind_shelf_areas <- as.data.table(matrix(nrow = (length(west_ind_north_latitudes)-1+length(west_ind_south_latitudes)-1)))
                                      
west_ind_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]

#loop for north
for (i in 1:(length(west_ind_north_latitudes)-1)) {
  #setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
  north_extent <- c(xmin(west_ind_spdf_mask_1s), xmax(west_ind_spdf_mask_1s), west_ind_north_latitudes[i], west_ind_north_latitudes[i+1])
  
  #crop raster segement based on bin extent
  segment_north <- crop(west_ind_spdf_mask_1s, extent(north_extent))
  
  #populate data table with latitudinal bin
  west_ind_shelf_areas[i, "latitude_start"] <- west_ind_north_latitudes[i]
  west_ind_shelf_areas[i, "latitude_end"] <- west_ind_north_latitudes[i+1]
  
  if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
    
  west_ind_shelf_areas[i, "area_equalareaproj"] <- 0
  west_ind_shelf_areas[i, "area_rasterarea"] <- 0
  west_ind_shelf_areas[i, "area_rgeos_gArea"] <- 0

  
  print(i)
    
  } else { #if there is shelf area within the bin, calculate area of slice
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_north)]
    
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
    
  #populate data table with raster area
  west_ind_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
    
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_north.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with polygon area using raster calculation
  west_ind_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
  
  #populate data table with polygon area using regeos calculation
  west_ind_shelf_areas[i, "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
#loop for south
for (i in 1:(length(west_ind_south_latitudes)-1)) {
  south_extent <- c(xmin(west_ind_spdf_mask_1s), xmax(west_ind_spdf_mask_1s), west_ind_south_latitudes[i+1], west_ind_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
  
  #raster segment
  segment_south <- crop(west_ind_spdf_mask_1s, extent(south_extent))
  
  #add latitude bin info to data table
    west_ind_shelf_areas[i+(length(west_ind_north_latitudes)-1), "latitude_start"] <- west_ind_south_latitudes[i]
  west_ind_shelf_areas[i+(length(west_ind_north_latitudes)-1), "latitude_end"] <- west_ind_south_latitudes[i+1]
  
  
  if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude

  west_ind_shelf_areas[i+(length(west_ind_north_latitudes)-1), "area_equalareaproj"] <- 0
  west_ind_shelf_areas[i+(length(west_ind_north_latitudes)-1), "area_rasterarea"] <- 0
    west_ind_shelf_areas[i+(length(west_ind_north_latitudes)-1), "area_rgeos_gArea"] <- 0
  
  print(i)
    
  } else {
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_south)]
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
    
  #populate data table with raster area
  west_ind_shelf_areas[i+(length(west_ind_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
    
  
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_south.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with area of polygon from raster::area function
  west_ind_shelf_areas[i+(length(west_ind_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
  
  #populate data table from rgeos area calculation for projected polygon
  west_ind_shelf_areas[i+(length(west_ind_north_latitudes)-1), "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons

ggplot(data = west_ind_shelf_areas) +
  geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
  labs(x=paste0("Latitude ","\u00B0","E"), y = "Area km^2") +
  theme_classic()


cor(west_ind_shelf_areas[,3:5], use = "complete.obs")
                   area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea          1.0000000          0.9999996        0.9999996
area_equalareaproj       0.9999996          1.0000000        1.0000000
area_rgeos_gArea         0.9999996          1.0000000        1.0000000
west_ind_shelf_areas[, percent_change := (area_rasterarea-data.table::shift(area_rasterarea, type = "lag"))/data.table::shift(area_rasterarea, type = "lag")][,area_1000s := area_rasterarea/1000]

west_ind_shelf_areas[,hemisphere := ifelse(latitude_end>0,"north","south")]

west_ind_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

west_ind_shelf_areas_highlight <- west_ind_shelf_areas[change_above_2fold != 0,]

west_ind_shelf_areas_stats <- table(west_ind_shelf_areas[,.(change_above_2fold, hemisphere)])

Model change for southern and northern hemisphere

#add mid latitude
west_ind_shelf_areas[,latitude_mid := abs((latitude_end+latitude_start)/2)]

west_ind_north_mod <- lm(data = west_ind_shelf_areas[hemisphere == "north"], area_rasterarea ~ latitude_mid)
summary(west_ind_north_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = west_ind_shelf_areas[hemisphere == 
    "north"])

Residuals:
   Min     1Q Median     3Q    Max 
-49907 -10358  -1891  14076  33614 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)    -837.4    12418.7  -0.067 0.947264    
latitude_mid   3767.6      717.4   5.252 0.000156 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24010 on 13 degrees of freedom
Multiple R-squared:  0.6797,    Adjusted R-squared:  0.655 
F-statistic: 27.58 on 1 and 13 DF,  p-value: 0.0001564
west_ind_south_mod <- lm(data = west_ind_shelf_areas[hemisphere == "south"], area_rasterarea ~ latitude_mid)
summary(west_ind_south_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = west_ind_shelf_areas[hemisphere == 
    "south"])

Residuals:
   Min     1Q Median     3Q    Max 
-22996 -12112  -2283   6339  44624 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)
(Intercept)    4120.2     8448.0   0.488    0.632
latitude_mid    700.9      406.6   1.724    0.104

Residual standard error: 17900 on 16 degrees of freedom
Multiple R-squared:  0.1566,    Adjusted R-squared:  0.1039 
F-statistic: 2.971 on 1 and 16 DF,  p-value: 0.104

Eastern Indian

east_ind_spdf_mask_1s

north_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), 0, ymax(east_ind_spdf_mask_1s))
south_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), ymin(east_ind_spdf_mask_1s), 0)

#crop east_ind raster above and below 0
east_ind_spdf_shift_agg_north <- crop(east_ind_spdf_mask_1s, extent(north_extent))

east_ind_spdf_shift_agg_south <- crop(east_ind_spdf_mask_1s, extent(south_extent))

#unfortunately, I think I may have to just do this manually (ugly, I know)

#all chunks for east indian
east_ind_north_latitudes <- seq(0, ymax(east_ind_spdf_mask_1s), by = 2)
east_ind_south_latitudes <- seq(0, ymin(east_ind_spdf_mask_1s), by = -2)

#setup data table to populate in loop, subtracting one to allow for bins
east_ind_shelf_areas <- as.data.table(matrix(nrow = (length(east_ind_north_latitudes)-1+length(east_ind_south_latitudes)-1)))
                                      
east_ind_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]

#loop for north
for (i in 1:(length(east_ind_north_latitudes)-1)) {
  #setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
  north_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), east_ind_north_latitudes[i], east_ind_north_latitudes[i+1])
  
  #crop raster segement based on bin extent
  segment_north <- crop(east_ind_spdf_mask_1s, extent(north_extent))
  
  #populate data table with latitudinal bin
  east_ind_shelf_areas[i, "latitude_start"] <- east_ind_north_latitudes[i]
  east_ind_shelf_areas[i, "latitude_end"] <- east_ind_north_latitudes[i+1]
  
  if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
    
  east_ind_shelf_areas[i, "area_equalareaproj"] <- 0
  east_ind_shelf_areas[i, "area_rasterarea"] <- 0
  east_ind_shelf_areas[i, "area_rgeos_gArea"] <- 0

  
  print(i)
    
  } else { #if there is shelf area within the bin, calculate area of slice
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_north)]
    
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
    
  #populate data table with raster area
  east_ind_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
    
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_north.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with polygon area using raster calculation
  east_ind_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
  
  #populate data table with polygon area using regeos calculation
  east_ind_shelf_areas[i, "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
#loop for south
for (i in 1:(length(east_ind_south_latitudes)-1)) {
  south_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), east_ind_south_latitudes[i+1], east_ind_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
  
  #raster segment
  segment_south <- crop(east_ind_spdf_mask_1s, extent(south_extent))
  
  #add latitude bin info to data table
    east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "latitude_start"] <- east_ind_south_latitudes[i]
  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "latitude_end"] <- east_ind_south_latitudes[i+1]
  
  
  if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude

  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_equalareaproj"] <- 0
  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rasterarea"] <- 0
    east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rgeos_gArea"] <- 0
  
  print(i)
    
  } else {
  
    #raster area calculation
      #get sizes of all cells in raster [km2]
    cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
    
    #delete NAs from vector of all raster cells
    cell_size_raster<-cell_size_raster[!is.na(segment_south)]
    #compute area of all cells in geo_raster
    #full area          <- total # grid cells     * median cell area (using median cares less about extreme values)
    segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
    
  #populate data table with raster area
  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
    
  
  #convert to spatial polygons to check area calculations
    
  #convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
  segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
  
  #  If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
  
    #project to equal earth area projection
  segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)

  #calculate area of the spatial object in m^2
    polygon_size.sp <- area(segment_south.sp.EA)

    #convert from m^2 to km^2
    segment_area_equalarea <- polygon_size.sp/1e6

    #populate data table with area of polygon from raster::area function
  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
  
  #and then plain and simple also using rgeos::gArea
  
  area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
  
  #populate data table from rgeos area calculation for projected polygon
  east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rgeos_gArea"] <-   area_rgeos_gArea
  
  print(i)
  } 
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
no non-missing arguments to min; returning Infno non-missing arguments to max; returning -Inf
[1] 24
no non-missing arguments to min; returning Infno non-missing arguments to max; returning -Inf
[1] 25
no non-missing arguments to min; returning Infno non-missing arguments to max; returning -Inf
[1] 26
no non-missing arguments to min; returning Infno non-missing arguments to max; returning -Inf
[1] 27
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons

ggplot(data = east_ind_shelf_areas) +
  geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
  geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
  labs(x=paste0("Latitude ","\u00B0","E"), y = "Area km^2") +
  theme_classic()


cor(east_ind_shelf_areas[,3:5], use = "complete.obs")
                   area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea          1.0000000          0.9999981        0.9999981
area_equalareaproj       0.9999981          1.0000000        1.0000000
area_rgeos_gArea         0.9999981          1.0000000        1.0000000
east_ind_shelf_areas[, percent_change := (area_rasterarea-data.table::shift(area_rasterarea, type = "lag"))/data.table::shift(area_rasterarea, type = "lag")][,area_1000s := area_rasterarea/1000]

east_ind_shelf_areas[,hemisphere := ifelse(latitude_end>0,"north","south")]

east_ind_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]

east_ind_shelf_areas_highlight <- east_ind_shelf_areas[change_above_2fold != 0,]

east_ind_shelf_areas_stats <- table(east_ind_shelf_areas[,.(change_above_2fold,hemisphere)])

Model change for southern and northern hemisphere

#add mid latitude
east_ind_shelf_areas[,latitude_mid := abs((latitude_end+latitude_start)/2)]

east_ind_north_mod <- lm(data = east_ind_shelf_areas[hemisphere == "north"], area_rasterarea ~ latitude_mid)
summary(east_ind_north_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = east_ind_shelf_areas[hemisphere == 
    "north"])

Residuals:
   Min     1Q Median     3Q    Max 
-34517 -14936  -1836  17006  39357 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)     42779      15428   2.773   0.0217 *
latitude_mid     1238       1216   1.018   0.3353  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 25500 on 9 degrees of freedom
Multiple R-squared:  0.1032,    Adjusted R-squared:  0.003607 
F-statistic: 1.036 on 1 and 9 DF,  p-value: 0.3353
east_ind_south_mod <- lm(data = east_ind_shelf_areas[hemisphere == "south"], area_rasterarea ~ latitude_mid)
summary(east_ind_south_mod)

Call:
lm(formula = area_rasterarea ~ latitude_mid, data = east_ind_shelf_areas[hemisphere == 
    "south"])

Residuals:
   Min     1Q Median     3Q    Max 
-44084 -34503 -19335  22903 130164 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)   
(Intercept)   54193.3    18114.7   2.992  0.00616 **
latitude_mid   -410.2      581.1  -0.706  0.48677   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 47040 on 25 degrees of freedom
Multiple R-squared:  0.01954,   Adjusted R-squared:  -0.01968 
F-statistic: 0.4983 on 1 and 25 DF,  p-value: 0.4868

Plots of latitude versus habitat availability

Include trend lines only for those with significant coefficients between latitude start and area^2 NOT: - East Indian Southern and Northern - East Pacific Southern - West Indian Southern

##east indian
#simulate data to plot trendline
east_ind_north_data <- data.table(latitude_mid = unique(east_ind_shelf_areas[latitude_end>0,]$latitude_mid))

east_ind_north_data[,area_1000s := east_ind_north_mod$coefficients[[1]]/1000+east_ind_north_mod$coefficients[[2]]/1000*latitude_mid]

east_ind_south_data <- data.table(latitude_mid = unique(east_ind_shelf_areas[latitude_end <0,]$latitude_mid))

east_ind_south_data[,area_1000s := east_ind_south_mod$coefficients[[1]]/1000+east_ind_south_mod$coefficients[[2]]/1000*latitude_mid]

#east indian
(area_latitude_east_ind  <- ggplot() +
#  geom_line(data = east_ind_north_data, aes(x=latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") + not significant
#  geom_line(data = east_ind_south_data, aes(x=latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") + not significant
  geom_point(data = east_ind_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18, size = 0.7) +
  geom_line(data = east_ind_shelf_areas, aes(x=latitude_start, y=area_1000s), size = 0.7) +
  geom_rug(data = east_ind_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x=paste0("Latitude ","\u00B0","E"), y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_viridis_d(option = "A", begin = 0.3, end = 0.7, name = "Associated Change\nin Shelf Area", labels = c("Contraction", "Expansion")) +
  ##annotate("text", x =22, y = 70000, label = "Eastern Indian Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(east_ind_shelf_areas$latitude_end), max(east_ind_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10)))


  ggsave(area_latitude_east_ind, filename = "area_latitude_east_ind_2degrees.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image

  
##west indian
west_ind_north_data <- data.table(latitude_mid = unique(west_ind_shelf_areas[latitude_end>0,]$latitude_mid))

west_ind_north_data[,area_1000s := west_ind_north_mod$coefficients[[1]]/1000+west_ind_north_mod$coefficients[[2]]/1000*latitude_mid]

west_ind_south_data <- data.table(latitude_mid = unique(west_ind_shelf_areas[latitude_end <0,]$latitude_mid))

west_ind_south_data[,area_1000s := west_ind_south_mod$coefficients[[1]]/1000+west_ind_south_mod$coefficients[[2]]/1000*latitude_mid]

(area_latitude_west_ind  <- ggplot() +
  geom_line(data = west_ind_north_data, aes(x=latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") +
 # geom_line(data = west_ind_south_data, aes(x=latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") + not significant
  geom_point(data = west_ind_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18, size = 0.7) + 
  geom_line(data = west_ind_shelf_areas, aes(x=latitude_start, y=area_1000s), size = 0.7) +
    geom_rug(data = west_ind_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x=paste0("Latitude ","\u00B0","E"), y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_viridis_d(option = "A", begin = 0.3, end = 0.7, name = "Associated Change\nin Shelf Area", labels = c("Contraction", "Expansion")) +
  #annotate("text", x = 30, y = 33000, label = "Western Indian Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(west_ind_shelf_areas$latitude_end), max(west_ind_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10)))

  ggsave(area_latitude_west_ind, filename = "area_latitude_west_ind_2degrees.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image
west_atl_north_data <- data.table(latitude_mid = unique(west_atl_shelf_areas[latitude_end>0,]$latitude_mid))

west_atl_north_data[,area_1000s := west_atl_north_mod$coefficients[[1]]/1000+west_atl_north_mod$coefficients[[2]]/1000*latitude_mid]

west_atl_south_data <- data.table(latitude_mid = unique(west_atl_shelf_areas[latitude_end <0,]$latitude_mid))

west_atl_south_data[,area_1000s := west_atl_south_mod$coefficients[[1]]/1000+west_atl_south_mod$coefficients[[2]]/1000*latitude_mid]

area_latitude_west_atl  <- ggplot() +
  geom_line(data = west_atl_north_data, aes(x=latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") +
  geom_line(data = west_atl_south_data, aes(x=-latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") +
  geom_point(data = west_atl_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18, size = 0.7) + 
  geom_line(data = west_atl_shelf_areas, aes(x=latitude_start, y=area_1000s), size = 0.7) +
  geom_rug(data = west_atl_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x=paste0("Latitude ","\u00B0","E"), y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_viridis_d(option = "A", begin = 0.3, end = 0.7, name = "Associated Change\nin Shelf Area", labels = c("Contraction", "Expansion")) +
  #annotate("text", x = 80, y = 120000, label = "Western Atlantic Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(west_atl_shelf_areas$latitude_end), max(west_atl_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10))

  ggsave(area_latitude_west_atl, filename = "area_latitude_west_atl_2degrees.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image
  
east_atl_north_data <- data.table(latitude_mid = unique(east_atl_shelf_areas[latitude_end>0,]$latitude_mid))

east_atl_north_data[,area_1000s := east_atl_north_mod$coefficients[[1]]/1000+east_atl_north_mod$coefficients[[2]]/1000*latitude_mid]

east_atl_south_data <- data.table(latitude_mid = unique(east_atl_shelf_areas[latitude_end <0,]$latitude_mid))

east_atl_south_data[,area_1000s := east_atl_south_mod$coefficients[[1]]/1000+east_atl_south_mod$coefficients[[2]]/1000*latitude_mid]  

area_latitude_east_atl  <- ggplot() +
  geom_line(data = east_atl_north_data, aes(x=latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") +
  geom_line(data = east_atl_south_data, aes(x=-latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") +
  geom_point(data = east_atl_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18, size = 0.7) + 
  geom_line(data = east_atl_shelf_areas, aes(x=latitude_start, y=area_1000s), size = 0.7) +
  geom_rug(data = east_atl_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x=paste0("Latitude ","\u00B0","E"), y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_viridis_d(option = "A", begin = 0.3, end = 0.7, name = "Associated Change\nin Shelf Area", labels = c("Contraction", "Expansion")) +
  #annotate("text", x = 82.5, y = 110000, label = "Eastern Atlantic Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(east_atl_shelf_areas$latitude_end), max(east_atl_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10))

  ggsave(area_latitude_east_atl, filename = "area_latitude_east_atl_2degrees.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image
  
  
east_pac_north_data <- data.table(latitude_mid = unique(east_pac_shelf_areas[latitude_end>0,]$latitude_mid))

east_pac_north_data[,area_1000s := east_pac_north_mod$coefficients[[1]]/1000+east_pac_north_mod$coefficients[[2]]/1000*latitude_mid]

east_pac_south_data <- data.table(latitude_mid = unique(east_pac_shelf_areas[latitude_end <0,]$latitude_mid))

east_pac_south_data[,area_1000s := east_pac_south_mod$coefficients[[1]]/1000+east_pac_south_mod$coefficients[[2]]/1000*latitude_mid]

area_latitude_east_pac  <- ggplot() +
  geom_line(data = east_pac_north_data, aes(x=latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") +
#  geom_line(data = east_pac_south_data, aes(x=latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") + not significant
  geom_point(data = east_pac_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18, size = 0.7) + 
  geom_line(data = east_pac_shelf_areas, aes(x=latitude_start, y=area_1000s), size = 0.7) +
  geom_rug(data = east_pac_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x=paste0("Latitude ","\u00B0","E"), y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_viridis_d(option = "A", begin = 0.3, end = 0.7, name = "Associated Change\nin Shelf Area", labels = c("Contraction", "Expansion")) +
  #annotate("text", x = 80, y = 130000, label = "Eastern Pacific Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(east_pac_shelf_areas$latitude_end), max(east_pac_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10))

  ggsave(area_latitude_east_pac, filename = "area_latitude_east_pac_2degrees.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image

  
west_pac_north_data <- data.table(latitude_mid = unique(west_pac_shelf_areas[latitude_end>0,]$latitude_mid))

west_pac_north_data[,area_1000s := west_pac_north_mod$coefficients[[1]]/1000+west_pac_north_mod$coefficients[[2]]/1000*latitude_mid]

west_pac_south_data <- data.table(latitude_mid = unique(west_pac_shelf_areas[latitude_end <0,]$latitude_mid))

west_pac_south_data[,area_1000s := west_pac_south_mod$coefficients[[1]]/1000+west_pac_south_mod$coefficients[[2]]/1000*latitude_mid]

(area_latitude_west_pac <- ggplot() +
  geom_line(data = west_pac_north_data, aes(x=latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") +
  geom_line(data = west_pac_south_data, aes(x=-latitude_mid, y = area_1000s), color = "gray60", size = 0.8, linetype = "longdash") +
  geom_point(data = west_pac_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18, size = 0.7) + 
  geom_line(data = west_pac_shelf_areas, aes(x=latitude_start, y=area_1000s), size = 0.7) +
  geom_rug(data = west_pac_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
 labs(x=paste0("Latitude ","\u00B0","E"), y = expression(paste("Area (1000s of ", km^{2},")"))) +
  scale_color_viridis_d(option = "A", begin = 0.3, end = 0.7, name = "Associated Change\nin Shelf Area", labels = c("Contraction", "Expansion")) +
  #annotate("text", x = 90, y = 130000, label = "Western Pacific Ocean") +
  geom_vline(xintercept = 0) +
  xlim(min(west_pac_shelf_areas$latitude_end), max(west_pac_shelf_areas$latitude_end)) +
  coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10)))

  

  ggsave(area_latitude_west_pac, filename = "area_latitude_west_pac_2degrees.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image

Dumby graph to just make additional legend component

legend_lat_area_regression <- get_legend(
  ggplot() +
  geom_line(data = west_pac_north_data, aes(x=latitude_mid, y = area_1000s, color = "value"), size = 0.8, linetype = "longdash") +
    scale_color_manual(values = "gray60", labels = "Area ~ Latitude\nLinear Regression") +
    coord_flip() +
  theme_classic() +
  theme(plot.margin = margin(10, 40, 10, 10), legend.title = element_blank()))

save(legend_lat_area_regression, here::here("Figures", "Figure3_5", "legend_lat_area_regression.RData"))
Error in save(legend_lat_area_regression, here::here("Figures", "Figure3_5",  : 
  object ‘here::here("Figures", "Figure3_5", "legend_lat_area_regression.RData")’ not found

How many experience ‘significant’ changes in habitat (at least -50% or +100% change from one bin to another) I will go with IUCN 50% loss -> vulnerable species designation.

Bin shifts –> contractions (loss of 50%) versus expansions (gain of 200%) versus neutral


library(ggrepel)
#call all objects in environment with "stats" string
stats_string<-grep("areas_stats",names(.GlobalEnv),value=TRUE)
stats_string_list<-do.call("list",mget(stats_string))
names(stats_string_list) #check
[1] "east_ind_shelf_areas_stats" "west_pac_shelf_areas_stats" "east_pac_shelf_areas_stats"
[4] "west_atl_shelf_areas_stats" "west_ind_shelf_areas_stats" "east_atl_shelf_areas_stats"
#rownames
stats_string_rownames <- rep(names(stats_string_list), each = 3)
stats_string_type <- rep(c("contraction", "neutral", "expansion"),times = 6)

#check <- c("Eastern Indian Ocean" ,"Western Pacific Ocean" ,"Eastern Pacific Ocean" ,"Western Atlantic Ocean" ,"Western Indian Ocean" ,"Eastern Atlantic Ocean")

significant_changes <- as.data.table(rbind(stats_string_list[[1]],stats_string_list[[2]],stats_string_list[[3]],stats_string_list[[4]],stats_string_list[[5]],stats_string_list[[6]]))

significant_changes[, region := stats_string_rownames][,type := stats_string_type]

#melt to plot
significant_changes.long <- melt(significant_changes, id.vars = c("region","type"), variable.name = "hemisphere", measure.vars = c("north", "south"))

#calculate percentages
significant_changes.long[,total_bins_hemisphere := sum(value),.(region, hemisphere)][,total_bins_region := sum(value),region][,percent_by_hemisphere := round(sum(value)/total_bins_hemisphere*100,2),.(region,hemisphere,type)][,percent_by_region := round(sum(value)/total_bins_region*100,2), .(region,type)]

significant_changes.long[,type := factor(type, levels = c("contraction","neutral","expansion"))][,region_names := factor(region, levels = c("east_atl_shelf_areas_stats", "west_atl_shelf_areas_stats", "east_ind_shelf_areas_stats", "west_ind_shelf_areas_stats" ,"east_pac_shelf_areas_stats" ,"west_pac_shelf_areas_stats"), labels = c("East Atlantic", "West Atlantic", "East Indian", "West Indian" ,"East Pacific" ,"West Pacific"))][,hemisphere := factor(hemisphere,levels = c("north","south"), labels = c("North","South"))]




blank_theme <- theme_minimal()+
  theme(
  axis.title.x = element_blank(),
  axis.title.y = element_blank(),
  panel.border = element_blank(),
  panel.grid=element_blank(),
  axis.ticks = element_blank(),
  plot.title=element_text(size=14, face="bold")
  )

#viridis magma palette, Contractions [1], expansions[2])
viridis_exp_cont <-viridis_pal(begin = 0.3, end = 0.7, option = "A")(2)

#by hemisphere

ggplot(data = significant_changes.long, aes(x="", y = percent_by_hemisphere, fill = type)) +
  geom_bar(stat = "identity", width = 1, alpha = 0.8) +
  coord_polar("y", start=0) +
  scale_fill_manual(values = c(viridis_exp_cont[1], "grey94", viridis_exp_cont[2]), name = "Shelf Area Change", labels = c("Contraction", "Neither", "Expansion")) +
  facet_grid(hemisphere~region_names) +
  geom_text_repel(aes(label = paste0(round(percent_by_hemisphere,1),"%")), size = 1, fontface = "bold", position = position_stack(vjust = 0.3)) +
  scale_x_discrete(expand = c(0,0)) +
  blank_theme +
  theme(axis.text.x=element_blank(),
        strip.text = element_text(size = 7),
        legend.title = element_text(size = 9), 
        legend.text = element_text(size = 7)) +
  guides(shape = guide_legend(override.aes = list(size = 0.5)), 
         fill = guide_legend(override.aes = list(size = 0.5)))

ggsave(filename = "figure6_habitatloss_gain_2fold_byhemisphere.jpg", height = 2, width = 6, unit = "in")
ggsave(filename = "figure6_habitatloss_gain_2fold_byhemisphere.eps", height = 2, width = 6, unit = "in")



#by region (hemisphere's compressed)
ggplot(data = unique(significant_changes.long[,.(region_names,type,percent_by_region)]), aes(x="", y = percent_by_region, fill = type)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start=0) +
  scale_fill_manual(values = c(viridis_exp_cont[1], "grey94", viridis_exp_cont[2]), name = "Shelf Area Change", labels = c("Contraction", "Neither", "Expansion")) +
  facet_wrap(~region_names) +
  geom_text(aes(label = paste0(percent_by_region,"%")), position = position_stack(vjust = 0.1), size = 2) +
  scale_x_discrete(expand = c(0,0)) +
  blank_theme +
  theme(axis.text.x=element_blank())

ggsave(filename = "figure6_habitatloss_gain_2fold_byregion.jpg", height = 4, width = 8, unit = "in")
ggsave(filename = "figure6_habitatloss_gain_2fold_byregion.eps", height = 4, width = 8, unit = "in")

NA
NA

Now, I should make maps for each of these regions

Used https://gist.github.com/valentinitnelav/c7598fcfc8e53658f66feea9d3bafb40 for instructions

library(ggspatial)

  world <- ne_countries(scale = "medium", returnclass = "sf")

# ~~~~~~~~~~~ Download shapefile from www.naturalearthdata.com ~~~~~~~~~~~ #
# Download countries data
#download.file(url = "http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries.zip", 
#              destfile = "ne_110m_admin_0_countries.zip")
# unzip the shapefile in the directory mentioned with "exdir" argument
#unzip(zipfile="ne_110m_admin_0_countries.zip", exdir = "ne_110m_admin_0_countries")
# delete the zip file
#file.remove("ne_110m_admin_0_countries.zip")
# read the shapefile with readOGR from rgdal package
NE_countries <- readOGR(dsn = "ne_110m_admin_0_countries", layer = "ne_110m_admin_0_countries")
OGR data source with driver: ESRI Shapefile 
Source: "/Users/zoekitchel/Documents/grad school/Rutgers/Repositories/shelf_habitat_distribution/ne_110m_admin_0_countries", layer: "ne_110m_admin_0_countries"
with 177 features
It has 94 fields
Integer64 fields read as strings:  POP_EST NE_ID 
class(NE_countries) # is a SpatialPolygonsDataFrame object
[1] "SpatialPolygonsDataFrame"
attr(,"package")
[1] "sp"
# ~~~~~~~~~~~ Split world map by "split line" ~~~~~~~~~~~ #

# shift central/prime meridian towards west – positive values only
shift <- 180 +30

# create "split line" to split country polygons
WGS84 <- CRS("+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0")
split.line <- SpatialLines(list(Lines(list(Line(cbind(180-shift,c(-90,90)))), ID="line")), 
                          proj4string=WGS84)

# NOTE - in case of TopologyException' errors when intersecting line with country polygons,
# apply the gBuffer solution suggested at:
# http://gis.stackexchange.com/questions/163445/r-solution-for-topologyexception-input-geom-1-is-invalid-self-intersection-er
NE_countries <- gBuffer(NE_countries, byid=TRUE, width=0)
Spatial object is not projected; GEOS expects planar coordinates
# intersecting line with country polygons
line.gInt <- gIntersection(split.line, NE_countries)
spgeom1 and spgeom2 have different proj4 strings
# create a very thin polygon (buffer) out of the intersecting "split line"
bf <- gBuffer(line.gInt, byid=TRUE, width=0.000001)  
Spatial object is not projected; GEOS expects planar coordinates
# split country polygons using intersecting thin polygon (buffer)
NE_countries.split <- gDifference(NE_countries, bf, byid=TRUE)
spgeom1 and spgeom2 have different proj4 strings
# plot(NE_countries.split) # check map
class(NE_countries.split) # is a SpatialPolygons object
[1] "SpatialPolygons"
attr(,"package")
[1] "sp"
# ~~~~~~~~~~~ Create graticules ~~~~~~~~~~~ #
# create a bounding box - world extent
b.box <- as(raster::extent(-180, 180, -90, 90), "SpatialPolygons")
# assign CRS to box
proj4string(b.box) <- WGS84
# create graticules/grid lines from box
grid <- gridlines(b.box, 
                  easts  = seq(from=-180, to=180, by=20),
                  norths = seq(from=-90, to=90, by=10))

# create labels for graticules
grid.lbl <- labels(grid, side = 1:4)

# transform labels from SpatialPointsDataFrame to a data table that ggplot can use
grid.lbl.DT <- data.table(grid.lbl@coords, grid.lbl@data)

# prepare labels with regular expression:
# - delete unwanted labels
grid.lbl.DT[, labels := gsub(pattern="180\\*degree|90\\*degree\\*N|90\\*degree\\*S", replacement="", x=labels)]
# - replace pattern "*degree" with "°" (* needs to be escaped with \\)
grid.lbl.DT[, lbl := gsub(pattern="\\*degree", replacement="°", x=labels)]
# - delete any remaining "*"
grid.lbl.DT[, lbl := gsub(pattern="*\\*", replacement="", x=lbl)]

# adjust coordinates of labels so that they fit inside the globe
grid.lbl.DT[, long := ifelse(coords.x1 %in% c(-180,180), coords.x1*175/180, coords.x1)]
grid.lbl.DT[, lat  := ifelse(coords.x2 %in% c(-90,90), coords.x2*82/90, coords.x2)]

# ~~~~~~~~~~~ Prepare data for ggplot, shift & project coordinates ~~~~~~~~~~~ #
# give the PORJ.4 string for Eckert IV projection ( changed to different projection, "+proj=eck4 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs" for eckert)
PROJ <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0" 

# transform graticules from SpatialLines to a data table that ggplot can use
grid.DT <- data.table(map_data(SpatialLinesDataFrame(sl=grid, 
                                                     data=data.frame(1:length(grid)), 
                                                     match.ID = FALSE)))
database does not (uniquely) contain the field 'name'.
# project coordinates
# assign matrix of projected coordinates as two columns in data table
grid.DT[, c("X","Y") := data.table(project(cbind(long, lat), proj=PROJ))]

# project coordinates of labels
grid.lbl.DT[, c("X","Y") := data.table(project(cbind(long, lat), proj=PROJ))]

# transform split country polygons in a data table that ggplot can use
Country.DT_shift <- data.table(map_data(as(NE_countries.split, "SpatialPolygonsDataFrame")))
database does not (uniquely) contain the field 'name'.
Country.DT <- data.table(map_data(as(NE_countries, "SpatialPolygonsDataFrame")))
# Shift coordinates
Country.DT_shift[, long.new := long + shift]
Country.DT_shift[, long.new := ifelse(long.new > 180, long.new-360, long.new)]

# project coordinates 
Country.DT[, c("X","Y") := data.table(project(cbind(long, lat), proj=PROJ))]
Country.DT_shift[, c("X","Y") := data.table(project(cbind(long.new, lat), proj=PROJ))]

# ~~~~~~~~~~~ Plot map ~~~~~~~~~~~ #
ggplot() + 
    # add projected countries
    geom_polygon(data = Country.DT_shift, 
                 aes(x = long.new+150, y = lat, group = group), 
                 colour = "gray70", 
                 fill = "gray90", 
                 size = 0.25) +
    # add graticules
    geom_path(data = grid.DT, 
              aes(x = X, y = Y, group = group), 
              linetype = "dotted", colour = "grey50", size = .25) +
    # add a bounding box (select graticules at edges)
    geom_path(data = grid.DT[(long %in% c(-180,180) & region == "NS")
                             |(long %in% c(-180,180) & lat %in% c(-90,90) & region == "EW")], 
              aes(x = X, y = Y, group = group), 
              linetype = "solid", colour = "black", size = .3) +
    # add graticule labels
    geom_text(data = grid.lbl.DT, # latitude
              aes(x = X, y = Y, label = lbl), 
              colour = "grey50", size = 2) +
    # ensures that one unit on the x-axis is the same length as one unit on the y-axis
    coord_equal() + # same as coord_fixed(ratio = 1)
    # set empty theme
    theme_void()

region_map_legend <- get_legend(region_maps[[6]])
range backtransformation not implemented in this coord; results may be wrong.

Combining plots

region_maps: “west_pac_spdf_shift”, “east_pac_spdf_shift”, “west_atl_spdf”, “west_ind_spdf”, “east_atl_spdf_nobuf”, “east_ind_spdf”

Plots of area versus latitude area_latitude_east_pac area_latitude_west_pac area_latitude_east_atl area_latitude_west_atl area_latitude_east_ind area_latitude_west_ind

Now, combine plots

library(egg)
library(ggpubr)

Attaching package: ‘ggpubr’

The following object is masked from ‘package:egg’:

    ggarrange

The following object is masked from ‘package:raster’:

    rotate
#west pacific
(west_pacific_merge_map_plot <- egg::ggarrange(region_maps[[1]], 
          area_latitude_west_pac 
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() ), 

          nrow = 1,
          top = T,
          widths = c(2,1)))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = west_pacific_merge_map_plot, filename = "west_pacific_merge_map_plot_2degrees.jpg", width = 7, height = 3, units = "in")

#east pacific
(east_pacific_merge_map_plot <- egg::ggarrange(region_maps[[2]], 
          area_latitude_east_pac 
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() )
          , 

          nrow = 1,
          top = T
          , 
          widths = c(2,1)
  ))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = east_pacific_merge_map_plot, filename = "east_pacific_merge_map_plot_2degrees.jpg", width = 7, height = 3, units = "in")

#both together
library(cowplot)

Attaching package: ‘cowplot’

The following object is masked from ‘package:ggpubr’:

    get_legend
figure_3_pacific_merge_top <- egg::ggarrange(region_maps[[1]] + theme(axis.title.x = element_blank(), plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          area_latitude_west_pac + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank(),
                     axis.title.x = element_blank(),
                     legend.position = "none",
                     plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          nrow = 1, ncol = 2, top = T, bottom = T, widths = c(1.5,1))
range backtransformation not implemented in this coord; results may be wrong.

figure_3_pacific_merge_bottom <- egg::ggarrange(region_maps[[2]] + theme(plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          area_latitude_east_pac + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank(),
                     legend.position = "none",
                     plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          nrow = 1, ncol = 2, top = T, bottom = T, widths = c(1.5,1))
range backtransformation not implemented in this coord; results may be wrong.
legend <- get_legend(area_latitude_east_pac)

figure_3_pacific_merge <- plot_grid(figure_3_pacific_merge_top, figure_3_pacific_merge_bottom, ncol = 1, nrow = 2, labels = c("a.","b."), axis = "l", align = "v", hjust = -7, rel_heights = c(1,1.5))

figure_3_pacific_merge_legend <- plot_grid(figure_3_pacific_merge, legend, ncol = 2, nrow = 1, rel_widths = c(4,1))

ggsave(figure_3_pacific_merge_legend, path = here::here("Figures", "Figure3_5"), filename = "Figure3_Pacific_latitude_area.jpg", height = 4, width = 6, unit = "in")

#east atlantic
(east_atlantic_merge_map_plot <- egg::ggarrange(region_maps[[5]], 
          area_latitude_east_atl
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() )
          , 

          nrow = 1,
          top = T,
          widths = c(2,1)))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = east_atlantic_merge_map_plot, filename = "east_atlantic_merge_map_plot_2degrees.jpg", width = 7, height = 3, units = "in")

#west atlantic
(west_atlantic_merge_map_plot <- egg::ggarrange(region_maps[[3]], 
          area_latitude_west_atl
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() )
          , 

          nrow = 1,
          top = T, 
          widths = c(2,1)))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = west_atlantic_merge_map_plot, filename = "west_atlantic_merge_map_plot_2degrees.jpg", width = 7, height = 3, units = "in")

#both together
library(cowplot)
figure_4_atlantic_merge_top <- egg::ggarrange(region_maps[[3]] + theme(axis.title.x = element_blank(), plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          area_latitude_west_atl + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank(),
                     axis.title.x = element_blank(),
                     legend.position = "none",
                     plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          nrow = 1, ncol = 2, top = T, bottom = T, widths = c(1.5,1))
range backtransformation not implemented in this coord; results may be wrong.

figure_4_atlantic_merge_bottom <- egg::ggarrange(region_maps[[5]] + theme(plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          area_latitude_east_atl + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank(),
                     legend.position = "none",
                     plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          nrow = 1, ncol = 2, top = T, bottom = T, widths = c(1.5,1))
range backtransformation not implemented in this coord; results may be wrong.
legend <- get_legend(area_latitude_east_atl)

figure_4_atlantic_merge <- plot_grid(figure_4_atlantic_merge_top, figure_4_atlantic_merge_bottom, ncol = 1, nrow = 2, labels = c("a.","b."), axis = "l", align = "v", hjust = -7, rel_heights = c(1.1,1))

figure_4_atlantic_merge_legend <- plot_grid(figure_4_atlantic_merge, legend, ncol = 2, nrow = 1, rel_widths = c(4,1))

ggsave(figure_4_atlantic_merge_legend, path = here::here("Figures", "Figure3_5"), filename = "Figure4_atlantic_latitude_area.jpg", height = 4, width = 6, unit = "in")

#west indian
(west_indian_merge_map_plot <- egg::ggarrange(region_maps[[4]], 
          area_latitude_west_ind 
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() )
          , 

          nrow = 1,
          top = T))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = west_indian_merge_map_plot, filename = "west_indian_merge_map_plot_2degrees.jpg", width = 7, height = 3, units = "in")


#east indian
(east_indian_merge_map_plot <- egg::ggarrange(region_maps[[6]], 
          area_latitude_east_ind
          + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank() )
          , 

          nrow = 1,
          top = T))
range backtransformation not implemented in this coord; results may be wrong.

ggsave(plot = east_indian_merge_map_plot, filename = "east_indian_merge_map_plot_2degrees.jpg", width = 7, height = 3, units = "in")

#both together
library(cowplot)
figure_5_indian_merge_top <- egg::ggarrange(region_maps[[4]] + theme(axis.title.x = element_blank(), plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          area_latitude_west_ind + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank(),
                     axis.title.x = element_blank(),
                     legend.position = "none",
                     plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          nrow = 1, ncol = 2, top = T, bottom = T, widths = c(1.5,1))
range backtransformation not implemented in this coord; results may be wrong.

figure_5_indian_merge_bottom <- egg::ggarrange(region_maps[[6]] + theme(plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          area_latitude_east_ind + 
               theme(axis.text.y = element_blank(),
                     axis.ticks.y = element_blank(),
                     axis.title.y = element_blank(),
                     legend.position = "none",
                     plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm")),
          nrow = 1, ncol = 2, top = T, bottom = T, widths = c(1.5,1))
range backtransformation not implemented in this coord; results may be wrong.
legend <- get_legend(area_latitude_east_ind)

figure_5_indian_merge <- plot_grid(figure_5_indian_merge_top, figure_5_indian_merge_bottom, ncol = 1, nrow = 2, labels = c("a.","b."), axis = "l", align = "v", hjust = -7, rel_heights = c(1,1.2))

figure_5_indian_merge_legend <- plot_grid(figure_5_indian_merge, legend, ncol = 2, nrow = 1, rel_widths = c(4,1))

ggsave(figure_5_indian_merge_legend, path = here::here("Figures", "Figure3_5"), filename = "Figure5_indian_latitude_area.jpg", height = 4, width = 6, unit = "in")

And now final merge for figures 3-5

indian_latitude_2_plots <- ggarrange(west_indian_merge_map_plot, east_indian_merge_map_plot, nrow = 2, ncol = 1)
ggsave(indian_latitude_2_plots, file = "indian_latitude_2_plots.jpg", height = 6, unit = "in")
Saving 7 x 6 in image
ggsave(indian_latitude_2_plots, file = "indian_latitude_2_plots.pdf", height = 6, unit = "in")

pacific_latitude_2_plots <- ggarrange(west_pacific_merge_map_plot, east_pacific_merge_map_plot, nrow = 2, ncol = 1)
ggsave(pacific_latitude_2_plots, file = "pacific_latitude_2_plots.jpg", height = 6, unit = "in")
ggsave(pacific_latitude_2_plots, file = "pacific_latitude_2_plots.pdf", height = 6, unit = "in")

atlantic_latitude_2_plots <- ggarrange(west_atlantic_merge_map_plot, east_atlantic_merge_map_plot, nrow = 2, ncol = 1)
ggsave(atlantic_latitude_2_plots, file = "atlantic_latitude_2_plots.jpg", height = 6, unit = "in")
ggsave(atlantic_latitude_2_plots, file = "atlantic_latitude_2_plots.pdf", height = 6, unit = "in")

Summary Table of Shifts away from Equator

regional_statistics <- data.table()
regional_statistics[,region := rep(c("West Pacific", "East Pacific", "West Atlantic", "West Indian", "East Atlantic", "East Indian"),each = 2)][,hemisphere := rep(c("Northern", "Southern"),6)][,contractions := as.numeric(NA)][,expansions := as.numeric(NA)][,coef := as.numeric(NA)][,pvalue := as.numeric(NA)]

shelf_areas <- c("west_pac_shelf_areas", "east_pac_shelf_areas", "west_atl_shelf_areas", "west_ind_shelf_areas", "east_atl_shelf_areas", "east_ind_shelf_areas")

north_mods <- c("west_pac_north_mod", "east_pac_north_mod", "west_atl_north_mod", "west_ind_north_mod", "east_atl_north_mod", "east_ind_north_mod")

south_mods <- c("west_pac_south_mod", "east_pac_south_mod", "west_atl_south_mod", "west_ind_south_mod", "east_atl_south_mod", "east_ind_south_mod")

for (i in 1:length(shelf_areas)) {

  this_shelf_area <- get(shelf_areas[i])
    #populate west pacific
    regional_statistics[region == unique(regional_statistics[,region])[i] & hemisphere == "Northern", "contractions"] <- round(this_shelf_area[latitude_end > 0 & change_above_2fold == -1,.N]/nrow(this_shelf_area[latitude_end > 0 & !is.na(percent_change)]),4)*100 #northern hemisphere contraction
    
    regional_statistics[region == unique(regional_statistics[,region])[i] & hemisphere == "Southern", "contractions"] <- round(this_shelf_area[latitude_end < 0 & change_above_2fold == -1,.N]/nrow(this_shelf_area[latitude_end < 0 & !is.na(percent_change)]),4)*100 #southern hemisphere contraction
    
    regional_statistics[region == unique(regional_statistics[,region])[i] & hemisphere == "Northern", "expansions"] <- round(this_shelf_area[latitude_end > 0 & change_above_2fold == 1,.N]/nrow(this_shelf_area[latitude_end > 0 & !is.na(percent_change)]),4)*100 #northern hemisphere expansion
    
    regional_statistics[region == unique(regional_statistics[,region])[i] & hemisphere == "Southern", "expansions"] <- round(this_shelf_area[latitude_end < 0 & change_above_2fold == 1,.N]/nrow(this_shelf_area[latitude_end < 0 & !is.na(percent_change)]),4)*100 #southern hemisphere expansion
    
    #northern mod
    regional_statistics[region == unique(regional_statistics[,region])[i] & hemisphere == "Northern", "coef"] <- round(get(north_mods[i])$coefficients[2],2)
    regional_statistics[region == unique(regional_statistics[,region])[i] & hemisphere == "Northern", "pvalue"] <- round(summary(get(north_mods[i]))$coefficients[,"Pr(>|t|)"][2],2)
    
    #southern mod
    regional_statistics[region == unique(regional_statistics[,region])[i] & hemisphere == "Southern", "coef"] <- round(get(south_mods[i])$coefficients[2],2)
    regional_statistics[region == unique(regional_statistics[,region])[i] & hemisphere == "Southern", "pvalue"] <- round(summary(get(south_mods[i]))$coefficients[,"Pr(>|t|)"][2],2)

}

view(regional_statistics)

#save
fwrite(regional_statistics, file = "Table1_regional_stats.csv")

save(significant_changes.long, significant_changes, file = "significant_changes_2degrees.Rdata")
LS0tCnRpdGxlOiAiMsuaIFNoaWZ0cyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKClRoaXMgc2NyaXB0IGlzIHZlcnkgc2ltaWxhciB0byBkZWdyZWVfc2hpZnRzX3Byb2plY3RlZCwgYnV0IGxvb2tzIGF0IDLLmiBzaGlmdHMgaW5zdGVhZCBvZiAxy5pzaGlmdHMuIAoKCkRlZ3JlZSBzaGlmdHMKClNlY29uZCBwYXJ0IG9mIHBhcGVyLCBpZiB3ZSBtb3ZlIGF3YXkgZnJvbSBlcXVhdG9yIGJ5IDLLmiBkZWdyZWUsIGhvdyBtdWNoIGhhYml0YXQgZG8gd2UgZ2FpbiBvciBsb3N0CgpJIG5lZWQgdG8gbG9vayBhdCBzaGVsZiBhcmVhIGJ5IGRlZ3JlZXMgbGF0aXR1ZGUKCmBgYHtyIHNldHVwfQpsaWJyYXJ5KHJhc3RlcikKbGlicmFyeShzZikKbGlicmFyeShuY2RmNCkKbGlicmFyeShybWFwc2hhcGVyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShkaXB0ZXN0KQpsaWJyYXJ5KG1vbWVudHMpCmxpYnJhcnkodmlyaWRpcykgI2NvbG9ycwpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoaHlkcm9UU00pICNoeXBzb21ldHJpYyBjdXJ2ZXMKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkobWFwdG9vbHMpCmxpYnJhcnkocmdkYWwpCmxpYnJhcnkocmdlb3MpCmxpYnJhcnkoU3BhREVTKQpsaWJyYXJ5KHJuYXR1cmFsZWFydGgpCmxpYnJhcnkocm5hdHVyYWxlYXJ0aGRhdGEpCmxpYnJhcnkoZ2duZXdzY2FsZSkKCgpldG9wb19zaGVsZl9kZiA8LSByZWFkUkRTKCJ+L0RvY3VtZW50cy9ncmFkIHNjaG9vbC9SdXRnZXJzL1JlcG9zaXRvcmllcy9zaGVsZl9oYWJpdGF0X2Rpc3RyaWJ1dGlvbi9ldG9wb19zaGVsZl9kZi5yZHMiKQojYnJpbmcgaW4gYmF0aHltZXRyeSBkYXRhIGZyYW1lIGZvciBzaGVsZiByZWdpb25zCgojTE1FcwpMTUVfc3BkZiA8LSByZWFkT0dSKCJMTUU2Ni9MTUVzNjYuc2hwIikgI3NwYXRpYWwgcG9pbnRzIGRhdGEgZnJhbWUgd2l0aCBhbGwgNjYgTE1FcwoKI3B1bGwgaW4gc2hhcGVmaWxlIGZvciBGQU8gc3RhdGlzdGljYWwgcmVnaW9uczogMy8xMS8yMDIxOiBodHRwOi8vd3d3LmZhby5vcmcvZ2VvbmV0d29yay9zcnYvZW4vbWFpbi5ob21lP3V1aWQ9YWMwMmE0NjAtZGE1Mi0xMWRjLTlkNzAtMDAxN2YyOTNiZDI4CkZBT19zcGRmIDwtIHJlYWRPR1IoIkZBT19BUkVBUy9GQU9fQVJFQVMuc2hwIikKCgoKCiNjb252ZXJ0IHRvIGVxdWFsIGFyZWEgcHJvamVjdGlvbgojZXF1YWxhcmVhcHJvamVjdGlvbjwtIGNycygiICtwcm9qPWVxZWFydGggIikKCiNUaGUgTGFtYmVydCBhemltdXRoYWwgZXF1YWwtYXJlYSBwcm9qZWN0aW9uIGlzIGEgcGFydGljdWxhciBtYXBwaW5nIGZyb20gYSBzcGhlcmUgdG8gYSBkaXNrLiBJdCBhY2N1cmF0ZWx5IHJlcHJlc2VudHMgYXJlYSBpbiBhbGwgcmVnaW9ucyBvZiB0aGUgc3BoZXJlLCBidXQgaXQgZG9lcyBub3QgYWNjdXJhdGVseSByZXByZXNlbnQgYW5nbGVzLgplcXVhbGFyZWFwcm9qZWN0aW9uPC0gY3JzKCIgK3Byb2o9bGFlYSAiKQoKCgoKYGBgCgpNYWtlIGJhdGh5bWV0cnkgZGF0YSBmcmFtZSBpbnRvIHJhc3RlciAodGhpcyB0YWtlcyBhIGJpdCkKCk5vdGUgdGhhdCBJIGFtIHRyeWluZyB0byB1c2UgdGhlIFtlcXVhbCBhcmVhIHByb2plY3Rpb25dKGh0dHBzOi8vd3d3LnItYmxvZ2dlcnMuY29tLzIwMTgvMDkvcXVpY2staGl0LXVzaW5nLXRoZS1uZXctZXF1YWwtZWFydGgtcHJvamVjdGlvbi1pbi1yLykKYGBge3IgYmF0aHkgdG8gcmFzdGVyfQoKZXRvcG9fc2hlbGZfcmFzdGVyIDwtIHJhc3RlckZyb21YWVooZXRvcG9fc2hlbGZfZGYsIGNycyA9IGNycyhMTUVfc3BkZikpCgojcmVjbGFzc2lmeSBhbGwgdmFsdWVzIDwyMDAwbSBpbiBkZXB0aCB0byAxIGluc3RlYWQgb2YgYWN0dWFsIGRlcHRoCmV0b3BvX3NoZWxmX3Jhc3RlciA8LSByZWNsYXNzaWZ5KGV0b3BvX3NoZWxmX3Jhc3RlcixjYmluZCgtSW5mLCBJbmYsIDEpKQoKYGBgCgoKU2hvdWxkIGdvIGJ5IHByb2plY3Rpb25zIG9mIHdoZXJlIHNwZWNpZXMgYXJlIG1vdmluZzoKIk1hcmluZSBzcGVjaWVzICh+ODAlIGJlaW5nIGVjdG90aGVybXMgaW4gdGhlIGRhdGFiYXNlOyBFeHRlbmRlZCBEYXRhIEZpZy4gMikgaGF2ZSBtb3ZlZCB0b3dhcmRzIHRoZSBwb2xlcyBhdCBhIG1lYW4gKMKxcy5lLm0uKSBwYWNlIG9mIDUuOTIgwrEgMC45NCBrbSB5cuKIkjEgKG9uZS1zYW1wbGUgU3R1ZGVudOKAmXMgdC10ZXN0OiB0PTYuMjY7IGQuZi4gcmVzaWR1YWxzPTIzOyBQPTIuMjDDlzEw4oCTNiksIHdoaWNoIGlzIGFsbW9zdCBzaXggdGltZXMgZmFzdGVyIHRoYW4gdGVycmVzdHJpYWwgc3BlY2llcyAob25lLXdheSBhbmFseXNpcyBvZiB2YXJpYW5jZSAoQU5PVkEpOiBGPTEyLjY4OyBkLmYuIGZhY3Rvcj0xOyBkLmYuIHJlc2lkdWFscz00NTsgUD04Ljg4w5cxMOKAkzQpLiIgTGVub2lyIDIwMjAKCjUuOTIga20gKiAxMCA9IDU5LjIga20gaW4gMTAgeWVhcnMKCjU5LjIga20gaXMgaG93IG1hbnkgZGVncmVlcz8KCjHCsCA9IDExMSBrbSwgMsuaID0gMjIyLzU5LjI9IDMuNzUsIHNvIHJvdWdobHkgMzUgeWVhcnMKc28sIAoKYGBge3IgcXVpY2sgY29udmVyc2lvbn0KMjIyLzU5LjIKCmBgYAoKMC41MzMzy5ogaXMgcmVwcmVzZW50YXRpdmUgb2YgZGVjYWRhbCBzaGlmdHMsIGJ1dCwgZm9yIGJldHRlciB2aXN1YWxpemF0aW9uIGxldCdzIGdvIHdpdGggMsuaIChyZXByZXNlbnRhdGl2ZSBvZiA0MCB5ZWFyIHNoaWZ0cykKCkkgd2lsbCBwdXQgYXJlYXMgaW50byAyy5ogQmlucyAoMTgwIHRvdGFsIGRlZ3JlZXMsIHNvIDE4MC8yPTkwIHRvdGFsIGxhdGl0dWRpbmFsIGJpbnMpCgpgYGB7cn0KMTgwLzIKYGBgCgpIb3cgZG9lcyBjb250aW5lbnRhbCBzaGVsZiBoYWJpdGF0IGNoYW5nZSB3aXRoIGxhdGl0dWRlPwoKTG9vayBhdCBjb250aWd1b3VzIGNvYXN0IGxpbmVzLgoKSSBhbSBnb2luZyB0byBsZWF2ZSBvdXQgQW50YXJjdGljYSAoNjEpIGFuZCB0aGUgQXJjdGljICg2NCkgYXMgQW50YXJjdGljYSBkcm93bmVkIG91dCBwYXR0ZXJucyBpbiBsb3dlciBsYXRpdHVkZXMgYW5kIEFyY3RpYyBkb2Vzbid0IGhhdmUgbXVjaCBoYWJpdGF0IHNoYWxsb3dlciB0aGFuIDIwMDBtIHRvIGJlZ2luIHdpdGguIAoKTkI6IEZvciBzdWJhcmN0aWMgcmVnaW9ucywgSSdtIGdvaW5nIGJ5IFt0aGlzIGZpZ3VyZV0oaHR0cHM6Ly9jb21tb25zLndpa2ltZWRpYS5vcmcvd2lraS9GaWxlOklCQ0FPX2JldGFtYXAuanBnKSB3aGVyZSB0aGVyZSBhcHBlYXIgdG8gYmUgc3BsaXRzIGJldHdlZW4gRXVyb3BlIGFuZCBHcmVlbmxhbmQsIEdyZWVubGFuZCBhbmQgQ2FuYWRhLCBhbmQgQ2FuYWRhIGFuZCBBbGFza2EuIFRoaXMgaXMgZm9yIHN1cmUgdXAgZm9yIGRpc2N1c3Npb24sIGJ1dCBpdCBzZWVtcyBsaWtlIG9uY2Ugc3BlY2llcyBnZXQgYWJvdmUgdGhlIGNvbnRpbmVudHMsIGl0IGlzIGEgYmlnIG9mIGEgZnJlZSBmb3IgYWxsLiAKCkVhc3Rlcm4gQXRsYW50aWMgKDMpCi0xOSwgMjAsIDIxLCAyMiwgMjMsIDI0LCAyNSwgMjYsIDI3LCAyOCwgMjksIDU4LCA1OSwgNjAsIDYyCgogIDMvOCB1cGRhdGUgKG1ha2UgbW9yZSBMTUVzIHNlcnZlIG11bHRpcGxlIGNvYXN0bGluZXMsIGdldCByaWQgb2YgZGV0YWNoZWQgaXNsYW5kcyAgICAgKE5ldyBaZWFsYW5kLCBHcmVlbmxhbmQsIEljZWxhbmQpLCBhbmQgaW5uZXIgaXNsYW5kcyAoYWthIEJhbHRpYyBTZWEsIG1lZGl0ZXJycmFuaWVhbiAgICAgc2VhLCByZWQgc2VhLCBibGFjayBzZWEpKQoKICAtMjAsIDU4LCA1NywgNTYsIDIxLCA2MCwgMjIsIDIzKiBCYWx0aWMgU2VhLCAyNCwgMjUsIDI3LCAyOCwgMjksIDI2ICogTWVkaXRlcnJhbmVhbiwgNjIqIEJsYWNrIFNlYQoKV2VzdGVybiBBdGxhbnRpYyAoMikKLSA1LCA2LCA3LCA4LCA5LCAxMiwgMTQsIDE1LCAxNiwgMTcsIDE4LCA2MywgNjYKCiAgLTMvOCB1cGRhdGUsIExFQVZFIE9VVCBHUkVFTkxBTkQKCiAgLSA2NiwgNTUsIDYzKiogSHVkc29uIEJheSwgOSwgOCwgNywgNiwgNSoqIEdPTSwgMTIsIDE3LCAxNiwgMTUsIDE0ICoqd2hhdCBhYm91dCAgICBndWxmIG9mIG1leGljbyBhbmQgZ3VsZiBvZiBDYWxpZm9ybmlhPwoKRWFzdGVybiBQYWNpZmljICgxKQotIDEsIDIsIDMsIDQsIDExLCAxMywgNTQsIDU1ICoqQmVhdWZvcnQgc2VhIHRoaW5seSBsaW5rZWQgdG8gQ2h1a2NoaSBTZWEsIHNvIHNwbGl0IGhlcmUsIDY1CgogIC0zLzggdXBkYXRlCiAgLTU0LCAxLCAyLCA1MywgNjUsIDMsIDQqKiBHT0MsIDExLCAxMwoKV2VzdGVybiBJbmRpYW4gKDQpCi0zMCwgMzEsIDMyLCAzMwoKICAtMy84IHVwZGF0ZQogIC0zMCwgMzEsIDMzKipibGFjayBzZWEsIDMyCgpFYXN0ZXJuIEluZGlhbiAoNSkKLTM0LCAzOCwgNDMsIDQ0LCA0NQoKCiAgLTMvOCB1cGRhdGUKICAtanVzdCB1c2UgRkFPIHN0YXRpc3RpY2FsIGFyZWEgNTcKCldlc3Rlcm4gUGFjaWZpYyAoNikKMSwJMzUsCTM2LAkzNywJMzksCTQwLAk0MSwJNDIsCTQ2LAk0NywJNDgsCTQ5LAk1MCwJNTEsCTUyLAk1MywJNTQsCTU2LAk1NywJNjUKCiAgLTMvOCB1cGRhdGUKICAtNDIsIDQxLCA1MCwgNTEsIDUyLCA1MywgMSw1NCwgNTYsIDU3LCA1OCwgMjAsYW5kIEZBTyBzdGF0aXN0aWNhbCByZWdpb25zIDcxIGFuZCA2MQoKTWVyZ2UgTE1FcyBpbnRvIDYgY29hc3RsaW5lIHJlZ2lvbnMKCk1hc2tzIGZvciByZWdpb25zIHRoYXQgYXJlIG5vdCBpbmNsdWRlZCBpbiBMTUVzIChjb29yZGluYXRlcyB0YWtlbiBmcm9tIEdvb2dsZSBtYXBzKS4gV2lsbCBhZGQgaW4gYXJlYXMgdGhhdCBkbyBOT1Qgb3ZlcmxhcCB3aXRoIGV4aXN0aW5nIExNRXMgYXQgdGhlIGVuZC4gCgpgYGB7ciBtaXNzaW5nIGZyb20gTE1Fc30KI1dlc3Rlcm4gUGFjaWZpYywgaW5jbHVkZSBGQU8gc3RhdGlzdGljYWwgcmVnaW9ucyA3MSBhbmQgNjEKd2VzdF9wYWNfZmFvIDwtIEZBT19zcGRmW0ZBT19zcGRmJEZfQ09ERSAlaW4lIGMoNjEsNzEpLF0KCiNhZGp1c3QgZXh0ZW50IGEgYml0IHRvIGdldCByaWQgb2Ygcm9ndWUgLTE3OCBwb2ludHMKd2VzdF9wYWNfZmFvIDwtIGNyb3Aod2VzdF9wYWNfZmFvLCBleHRlbnQoOTQsIDE4MCwgLTI4LjE1LCA2Ni40MTQ4KSkKCndlc3RfcGFjX2Zhby5yYXN0ZXIgPC0gY3JvcChldG9wb19zaGVsZl9yYXN0ZXIsIGV4dGVudCg5NCwgMTgwLCAtMjguMTUsIDY2LjQxNDgpKQp3ZXN0X3BhY19mYW8ucmFzdGVyIDwtIG1hc2sod2VzdF9wYWNfZmFvLnJhc3Rlciwgd2VzdF9wYWNfZmFvKQoKI0Vhc3Rlcm4gSW5kaWFuIE9jZWFuCmVhc3RfaW5kX2ZhbyA8LSBGQU9fc3BkZltGQU9fc3BkZiRGX0NPREUgPT0gNTcsXQoKCmBgYAoKYGBge3IgbWVyZ2luZyBMTUVzfQp3ZXN0X3BhYyA8LSBjKDQyLCA0MSwgNTAsIDUxLCA1MiwgNTMsIDEsNTQsIDU2LCA1NywgNTgsIDIwKQplYXN0X3BhYyA8LSBjKDU0LCAxLCAyLCA1MywgNjUsIDMsIDQsIDExLCAxMykKd2VzdF9hdGwgPC0gYyg2NiwgNTUsIDYzLCA5LCA4LCA3LCA2LCA1LCAxMiwgMTcsIDE2LCAxNSwgMTQpCmVhc3RfYXRsIDwtIGMoMjAsIDU4LCA1NywgNTYsIDIxLCA2MCwgMjIsIDIzLCAyNCwgMjUsIDI3LCAyOCwgMjksIDI2LCA2MikKd2VzdF9pbmQgPC0gYygzMCwgMzEsIDMzLCAzMikKCiNzdWJyZWdpb25zIGJhc2VkIG9uIExNRV9udW1iZXIKd2VzdF9wYWNfc3BkZiA8LSBMTUVfc3BkZlsoTE1FX3NwZGYkTE1FX05VTUJFUikgJWluJSB3ZXN0X3BhYyxdCmVhc3RfcGFjX3NwZGYgPC0gTE1FX3NwZGZbKExNRV9zcGRmJExNRV9OVU1CRVIpICVpbiUgZWFzdF9wYWMsXQp3ZXN0X2F0bF9zcGRmIDwtIExNRV9zcGRmWyhMTUVfc3BkZiRMTUVfTlVNQkVSKSAlaW4lIHdlc3RfYXRsLF0Kd2VzdF9pbmRfc3BkZiA8LSBMTUVfc3BkZlsoTE1FX3NwZGYkTE1FX05VTUJFUikgJWluJSB3ZXN0X2luZCxdCmVhc3RfYXRsX3NwZGYgPC0gTE1FX3NwZGZbKExNRV9zcGRmJExNRV9OVU1CRVIpICVpbiUgZWFzdF9hdGwsXQplYXN0X2luZF9zcGRmIDwtIGVhc3RfaW5kX2ZhbwoKI2ZvciBzdWJyZWdpb25zIHRoYXQgc3BhbiAzNjAsIHdlIG5lZWQgdG8gY2hhbmdlIENSUyBhIGJpdApuZXdDUlNfd2VzdCA8LSAiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQgK2xvbl93cmFwPTE4MCIgI3RoaXMgc2hpZnRzIDE4MCBkZWdyZWVzCndlc3RfcGFjX3NwZGZfc2hpZnQgPC0gc3BUcmFuc2Zvcm0od2VzdF9wYWNfc3BkZiwgQ1JTKG5ld0NSU193ZXN0KSkKd2VzdF9wYWNfc3BkZl9zaGlmdCA8LSBnQnVmZmVyKHdlc3RfcGFjX3NwZGZfc2hpZnQsIGJ5aWQ9VFJVRSwgd2lkdGg9MCkgI2dldHMgcmlkIG9mIGJ1ZmZlcnMsIGFsbG93cyBmb3IgdW5pb24KCm5ld0NSU19lYXN0IDwtICIrcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCArbG9uX3dyYXA9MTgwIiAjdGhpcyBzaGlmdHMgMTgwIGRlZ3JlZXMKZWFzdF9wYWNfc3BkZl9zaGlmdCA8LSBzcFRyYW5zZm9ybShlYXN0X3BhY19zcGRmLCBDUlMobmV3Q1JTX2Vhc3QpKQplYXN0X3BhY19zcGRmX3NoaWZ0IDwtIGdCdWZmZXIoZWFzdF9wYWNfc3BkZl9zaGlmdCwgYnlpZD1UUlVFLCB3aWR0aD0wKSAjZ2V0cyByaWQgb2YgYnVmZmVycywgYWxsb3dzIGZvciB1bmlvbgoKI3JvdGF0ZSByYXN0ZXIgZm9yIGJhdGh5bWV0cnkgKGd1aWRlZCBieSBleHRlbnQgb2YgZXRvcG9zaGVsZiByYXN0ZXIsICB0aGF0J3Mgd2h5IHdhY2t5ICNzKQp4MSA8LSBjcm9wKGV0b3BvX3NoZWxmX3Jhc3RlciwgZXh0ZW50KC0xODAuMDE2NywgLTAuMDE2NywgLTkwLjAxNjY3LCA5MC4wMTY2NykpCngyIDwtIGNyb3AoZXRvcG9fc2hlbGZfcmFzdGVyLCBleHRlbnQoMCwgMTgwLjAxNjcsIC05MC4wMTY2NywgOTAuMDE2NjcpKSAgIApleHRlbnQoeDEpIDwtIGMoMTgwLjAxNjcsIDM2MC4wMTY3LCAtOTAuMDE2NjcgLCA5MC4wMTY2NykKZXRvcG9fc2hlbGZfcmFzdGVyXzE4MCA8LSBtZXJnZSh4MSwgeDIpCgojZ2V0IHJpZCBvZiBidWZmZXIgZm9yIGVhc3QgYXRsIGFzIHdlbGwgdG8gYWxsb3cgZm9yIHVuaW9uCgplYXN0X2F0bF9zcGRmX25vYnVmIDwtIGdCdWZmZXIoZWFzdF9hdGxfc3BkZiwgYnlpZD1UUlVFLCB3aWR0aD0wKQoKcmVnaW9uX25hbWVzIDwtIGMoIndlc3RfcGFjX3NwZGZfc2hpZnQiLCAiZWFzdF9wYWNfc3BkZl9zaGlmdCIsICJ3ZXN0X2F0bF9zcGRmIiwgIndlc3RfaW5kX3NwZGYiLCAiZWFzdF9hdGxfc3BkZl9ub2J1ZiIsICJlYXN0X2luZF9zcGRmIikKCgoKI2Rpc3NvbHZlIGFsbCBwb2x5Z29ucyBieSByZWdpb24KZm9yIChpIGluIDE6bGVuZ3RoKHJlZ2lvbl9uYW1lcykpIHsKICBuYW1lIDwtIHBhc3RlMChyZWdpb25fbmFtZXNbaV0sICJfYWdnIikKICBhc3NpZ24obmFtZSwgZ1VuYXJ5VW5pb24oZ2V0KHJlZ2lvbl9uYW1lc1tpXSkpKSAjZGlzc29sdmUgcG9seWdvbnMgd2l0aGluIGNvYXN0bGluZSByZWdpb24gaW50byBvbmUKfQoKYGBgCgoKRXh0cmFjdCBiYXRoeW1ldHJ5IGRhdGEgZnJvbSBwb2x5Z29uIG9ubHkgdG8gbWFrZSBzdXJlIHdlJ3JlIGxpbWl0aW5nIHRvIHNoZWxmIHJlZ2lvbnMgYWJvdmUgMjAwMCBtZXRlcnMKCmBgYHtyIHBvbHlnb24gdG8gcmFzdGVyfQoKcmVnaW9uX25hbWVzX3NoaWZ0IDwtIHJlZ2lvbl9uYW1lc1sxOjJdCgoKcmVnaW9uX25hbWVzX25vc2hpZnQgPC0gcmVnaW9uX25hbWVzWzM6Nl0KCgpmb3IgKGkgaW4gMTpsZW5ndGgocmVnaW9uX25hbWVzX25vc2hpZnQpKSB7CiNjcm9wIGJhdGh5bWV0cnkgbGF5ZXIgdG8gTE1FIHN1YnNldCAoY29udGluZW50YWwgc2hlbGYgaGFiaXRhdCBpbiBMTUVzKQogIHJhc3Rlcl9leHRlbnQgPC0KICAgICAgIGNyb3AoZXRvcG9fc2hlbGZfcmFzdGVyLCBleHRlbnQoZ2V0KHBhc3RlMChyZWdpb25fbmFtZXNfbm9zaGlmdFtpXSwgIl9hZ2ciKSkpKQoKI3doaWNoIGFyZWFzIG9mIHJhc3RlciBmYWxsIHdpdGhpbiBib3JkZXJzPwogIGFzc2lnbihwYXN0ZTAocmVnaW9uX25hbWVzX25vc2hpZnRbaV0sICJfbWFzayIpLAogICAgICAgbWFzayhyYXN0ZXJfZXh0ZW50LCBnZXQocGFzdGUwKHJlZ2lvbl9uYW1lc19ub3NoaWZ0W2ldLCAiX2FnZyIpKSkpCiAgCiAgICBhc3NpZ24ocGFzdGUwKHJlZ2lvbl9uYW1lc19ub3NoaWZ0W2ldLCAiX21hc2tfMXMiKSwKICAgICAgIHJlY2xhc3NpZnkoZ2V0KHBhc3RlMChyZWdpb25fbmFtZXNfbm9zaGlmdFtpXSwgIl9tYXNrIikpLCBjYmluZCgtSW5mLCBJbmYsIDEpKSkKCiAgCgp9CgojZWRpdCBmb3IgZWFzdF9wYWNfc3BkZl9zaGlmdCBhbmQgd2VzdF9wYWNfc3BkZl9zaGlmdCAoKzE4MMuaKQoKZm9yIChpIGluIDE6bGVuZ3RoKHJlZ2lvbl9uYW1lc19zaGlmdFsxOjJdKSkgewojY3JvcCBiYXRoeSBsYXllciB0byBMTUUgc3Vic2V0CiAgcmFzdGVyX2V4dGVudCA8LQogICAgICAgY3JvcChldG9wb19zaGVsZl9yYXN0ZXJfMTgwLCBleHRlbnQoZ2V0KHBhc3RlMChyZWdpb25fbmFtZXNfc2hpZnRbaV0sICJfYWdnIikpKSkKCiN3aGljaCBhcmVhcyBvZiByYXN0ZXIgZmFsbCB3aXRoaW4gYm9yZGVycz8KICBhc3NpZ24ocGFzdGUwKHJlZ2lvbl9uYW1lc19zaGlmdFtpXSwgIl9tYXNrIiksCiAgICAgICBtYXNrKHJhc3Rlcl9leHRlbnQsIGdldChwYXN0ZTAocmVnaW9uX25hbWVzX3NoaWZ0W2ldLCAiX2FnZyIpKSkpCiAgCiAgICBhc3NpZ24ocGFzdGUwKHJlZ2lvbl9uYW1lc19zaGlmdFtpXSwgIl9tYXNrXzFzIiksCiAgICAgICByZWNsYXNzaWZ5KGdldChwYXN0ZTAocmVnaW9uX25hbWVzX3NoaWZ0W2ldLCAiX21hc2siKSksIGNiaW5kKC1JbmYsIEluZiwgMSkpKQoKfQoKYGBgCgpNZXJnZSBpbiBhcmVhcyB1bmFjY291bnRlZCBmb3IgYnkgTE1FcyAoUGhpbGlwcGluZXMsIFN1bWF0cmEsIFBhcHVhIE5ldyBHdWluZWEpCgpgYGB7ciBtZXJnZSBub24tTE1FIHJlZ2lvbnN9CiN3ZXN0ZXJuIHBhY2lmaWMgb2NlYW4Kd2VzdF9wYWNfc3BkZl9tYXNrX2Z1bGwgPC0gbWVyZ2Uod2VzdF9wYWNfZmFvLnJhc3Rlciwgd2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzKQpgYGAKCgpIb3cgdG8gY2FsY3VsYXRlIGFyZWE/CgotIHJhc3Rlcjo6YXJlYSgpIFRISVMgSVMgV0hBVCBXRSdSRSBHT0lORyBXSVRIClJhc3RlciBvYmplY3RzOiBDb21wdXRlIHRoZSBhcHByb3hpbWF0ZSBzdXJmYWNlIGFyZWEgb2YgY2VsbHMgaW4gYW4gdW5wcm9qZWN0ZWQgKGxvbmdpdHVkZS9sYXRpdHVkZSkgUmFzdGVyIG9iamVjdC4gSXQgaXMgYW4gYXBwcm94aW1hdGlvbiBiZWNhdXNlIGFyZWEgaXMgY29tcHV0ZWQgYXMgdGhlIGhlaWdodCAobGF0aXR1ZGluYWwgc3Bhbikgb2YgYSBjZWxsICh3aGljaCBpcyBjb25zdGFudCBhbW9uZyBhbGwgY2VsbHMpIHRpbWVzIHRoZSB3aWR0aCAobG9uZ2l0dWRpbmFsIHNwYW4pIGluIHRoZSAobGF0aXR1ZGluYWwpIG1pZGRsZSBvZiBhIGNlbGwuIFRoZSB3aWR0aCBpcyBzbWFsbGVyIGF0IHRoZSBwb2xld2FyZCBzaWRlIHRoYW4gYXQgdGhlIGVxdWF0b3Itd2FyZCBzaWRlIG9mIGEgY2VsbC4gVGhpcyB2YXJpYXRpb24gaXMgZ3JlYXRlc3QgbmVhciB0aGUgcG9sZXMgYW5kIHRoZSB2YWx1ZXMgYXJlIHRodXMgbm90IHZlcnkgcHJlY2lzZSBmb3IgdmVyeSBoaWdoIGxhdGl0dWRlcy4gSWYgeCBpcyBhIFJhc3Rlciogb2JqZWN0OiBSYXN0ZXJMYXllciBvciBSYXN0ZXJCcmljay4gQ2VsbCB2YWx1ZXMgcmVwcmVzZW50IHRoZSBzaXplIG9mIHRoZSBjZWxsIGluIGttMiwgb3IgdGhlIHJlbGF0aXZlIHNpemUgaWYgd2VpZ2h0cz1UUlVFCgoKCi0gcmFzdGVyOjphcmVhKCkgClNwYXRpYWxQb2x5Z29uczogQ29tcHV0ZSB0aGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBmZWF0dXJlcy4gV29ya3MgZm9yIGJvdGggcGxhbmFyIGFuZCBhbmd1bGFyIChsb24vbGF0KSBjb29yZGluYXRlIHJlZmVyZW5jZSBzeXN0ZW1zLiBJZiB4IGlzIGEgU3BhdGlhbFBvbHlnb25zKiBvYmplY3Q6IGFyZWEgb2YgZWFjaCBzcGF0aWFsIG9iamVjdCBpbiBzcXVhcmVkIG1ldGVycyBpZiB0aGUgQ1JTIGlzIGxvbmdpdHVkZS9sYXRpdHVkZSwgb3IgaW4gc3F1YXJlZCBtYXAgdW5pdHMgKHR5cGljYWxseSBtZXRlcikKCi0gcmdlb3M6OmdBcmVhClJldHVybnMgdGhlIGFyZWEgb2YgdGhlIGdlb21ldHJ5IGluIHRoZSB1bml0cyBvZiB0aGUgY3VycmVudCBwcm9qZWN0aW9uLiBCeSBkZWZpbml0aW9uIG5vbi1bTVVMVEldUE9MWUdPTiBnZW9tZXRyaWVzIGhhdmUgYW4gYXJlYSBvZiAwLiBUaGUgYXJlYSBvZiBhIFBPTFlHT04gaXMgdGhlIGFyZWEgb2YgaXRzIHNoZWxsIGxlc3MgdGhlIGFyZWEgb2YgYW55IGhvbGVzLiBOb3RlIHRoYXQgdGhpcyB2YWx1ZSBtYXkgYmUgZGlmZmVyZW50IGZyb20gdGhlIGFyZWEgc2xvdCBvZiB0aGUgUG9seWdvbnMgY2xhc3MgYXMgdGhpcyB2YWx1ZSBkb2VzIG5vdCBzdWJ0cmFjdCB0aGUgYXJlYSBvZiBhbnkgaG9sZXMgaW4gdGhlIGdlb21ldHJ5LgoKCk5vdywgd2Ugd2lsbCBzcGxpdCBlYWNoIGNvYXN0bGluZSByYXN0ZXIgaW50byBsYXRpdHVkaW5hbCBiaW5zIG9mIDLLmgoKSWYgdGhlc2UgaGF2ZSBhbHJlYWR5IGJlZW4gZG9uZSwgbG9hZCBpbiBmcm9tIGZpbGUgaW5zdGVhZCBvZiByZWNyZWF0aW5nIGJlY2F1c2UgdGhhdCB0YWtlcyBzb21lIHRpbWUuCmBgYHtyIGxvYWQgaW4gZnJvbSBmaWxlc30KbG9hZCgid2VzdF9wYWNfc2hlbGZfYXJlYXNfMmRlZ3JlZXMuUmRhdGEiKQpsb2FkKCJ3ZXN0X2F0bF9zaGVsZl9hcmVhc18yZGVncmVlcy5SZGF0YSIpCmxvYWQoIndlc3RfaW5kX3NoZWxmX2FyZWFzXzJkZWdyZWVzLlJkYXRhIikKbG9hZCgiZWFzdF9wYWNfc2hlbGZfYXJlYXNfMmRlZ3JlZXMuUmRhdGEiKQpsb2FkKCJlYXN0X2F0bF9zaGVsZl9hcmVhc18yZGVncmVlcy5SZGF0YSIpCmxvYWQoImVhc3RfaW5kX3NoZWxmX2FyZWFzXzJkZWdyZWVzLlJkYXRhIikKYGBgCgoKV2VzdGVybiBQYWNpZmljCmBgYHtyIHNwbGl0IHJhc3RlciBmb3Igd2VzdGVybiBwYWNpZmljfQpub3J0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfcGFjX3NwZGZfbWFza19mdWxsKSwgeG1heCh3ZXN0X3BhY19zcGRmX21hc2tfZnVsbCksIDAsIHltYXgod2VzdF9wYWNfc3BkZl9tYXNrX2Z1bGwpKQpzb3V0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfcGFjX3NwZGZfbWFza19mdWxsKSwgeG1heCh3ZXN0X3BhY19zcGRmX21hc2tfZnVsbCksIHltaW4od2VzdF9wYWNfc3BkZl9tYXNrX2Z1bGwpLCAwKQoKI2Nyb3Agd2VzdF9wYWMgcmFzdGVyIGFib3ZlIGFuZCBiZWxvdyAwCndlc3RfcGFjX3NwZGZfc2hpZnRfYWdnX25vcnRoIDwtIGNyb3Aod2VzdF9wYWNfc3BkZl9tYXNrX2Z1bGwsIGV4dGVudChub3J0aF9leHRlbnQpKQoKd2VzdF9wYWNfc3BkZl9zaGlmdF9hZ2dfc291dGggPC0gY3JvcCh3ZXN0X3BhY19zcGRmX21hc2tfZnVsbCwgZXh0ZW50KHNvdXRoX2V4dGVudCkpCgojdW5mb3J0dW5hdGVseSwgSSB0aGluayBJIG1heSBoYXZlIHRvIGp1c3QgZG8gdGhpcyBtYW51YWxseSAodWdseSwgSSBrbm93KQoKI2FsbCBjaHVua3MgZm9yIHdlc3QgcGFjaWZpYwp3ZXN0X3BhY19ub3J0aF9sYXRpdHVkZXMgPC0gc2VxKDAsIHltYXgod2VzdF9wYWNfc3BkZl9tYXNrX2Z1bGwpLCBieSA9IDIpCndlc3RfcGFjX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbih3ZXN0X3BhY19zcGRmX21hc2tfZnVsbCksIGJ5ID0gLTIpCgojc2V0dXAgZGF0YSB0YWJsZSB0byBwb3B1bGF0ZSBpbiBsb29wLCBzdWJ0cmFjdGluZyBvbmUgdG8gYWxsb3cgZm9yIGJpbnMKd2VzdF9wYWNfc2hlbGZfYXJlYXMgPC0gYXMuZGF0YS50YWJsZShtYXRyaXgobnJvdyA9IChsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xK2xlbmd0aCh3ZXN0X3BhY19zb3V0aF9sYXRpdHVkZXMpLTEpKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKd2VzdF9wYWNfc2hlbGZfYXJlYXNbLCBsYXRpdHVkZV9zdGFydCA6PSBhcy5udW1lcmljKFYxKV1bLCBsYXRpdHVkZV9lbmQgOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yYXN0ZXJhcmVhIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfZXF1YWxhcmVhcHJvaiA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX3JnZW9zX2dBcmVhIDo9IGFzLm51bWVyaWMoVjEpXVssIFYxIDo9IE5VTExdCgojbG9vcCBmb3Igbm9ydGgKZm9yIChpIGluIDE6KGxlbmd0aCh3ZXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpKSB7CiAgI3NldHRpbmcgdXAgZXh0ZW50IGZvciBzbGljaW5nIGJ5IG1pbiBhbmQgbWF4IGxvbmdpdHVkZXMsIGFuZCBpIHRvIGkrMSBsYXRpdHVkZXMKICBub3J0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfcGFjX3NwZGZfbWFza19mdWxsKSwgeG1heCh3ZXN0X3BhY19zcGRmX21hc2tfZnVsbCksIHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlc1tpXSwgd2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3Aod2VzdF9wYWNfc3BkZl9tYXNrX2Z1bGwsIGV4dGVudChub3J0aF9leHRlbnQpKQogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggbGF0aXR1ZGluYWwgYmluCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gd2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzW2ldCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImxhdGl0dWRlX2VuZCJdIDwtIHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlc1tpKzFdCiAgCiAgaWYoYWxsKGlzLm5hKHZhbHVlcyhzZWdtZW50X25vcnRoKSkpKSB7ICNpZiB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgd2l0aGluIGEgYmluLCBhbGwgYXJlYSA9IDAKICAgIAogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSAwCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKCiAgCiAgcHJpbnQoaSkKICAgIAogIH0gZWxzZSB7ICNpZiB0aGVyZSBpcyBzaGVsZiBhcmVhIHdpdGhpbiB0aGUgYmluLCBjYWxjdWxhdGUgYXJlYSBvZiBzbGljZQogIAogICAgI3Jhc3RlciBhcmVhIGNhbGN1bGF0aW9uCiAgICAgICNnZXQgc2l6ZXMgb2YgYWxsIGNlbGxzIGluIHJhc3RlciBba20yXQogICAgY2VsbF9zaXplX3Jhc3RlcjwtYXJlYShzZWdtZW50X25vcnRoLCBuYS5ybT1UUlVFLCB3ZWlnaHRzPUZBTFNFKQogICAgCiAgICAjZGVsZXRlIE5BcyBmcm9tIHZlY3RvciBvZiBhbGwgcmFzdGVyIGNlbGxzCiAgICBjZWxsX3NpemVfcmFzdGVyPC1jZWxsX3NpemVfcmFzdGVyWyFpcy5uYShzZWdtZW50X25vcnRoKV0KICAgIAogICAgI2NvbXB1dGUgYXJlYSBvZiBhbGwgY2VsbHMgaW4gZ2VvX3Jhc3RlcgogICAgI2Z1bGwgYXJlYSAgICAgICAgICA8LSB0b3RhbCAjIGdyaWQgY2VsbHMgICAgICogbWVkaWFuIGNlbGwgYXJlYSAodXNpbmcgbWVkaWFuIGNhcmVzIGxlc3MgYWJvdXQgZXh0cmVtZSB2YWx1ZXMpCiAgICBzZWdtZW50X2FyZWFfcmFzdGVyIDwtIGxlbmd0aChjZWxsX3NpemVfcmFzdGVyKSptZWRpYW4oY2VsbF9zaXplX3Jhc3RlcikgI2luIGttXjIKICAgIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcmFzdGVyIGFyZWEKICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfbm9ydGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X25vcnRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X25vcnRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfbm9ydGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X25vcnRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcG9seWdvbiBhcmVhIHVzaW5nIHJhc3RlciBjYWxjdWxhdGlvbgogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfbm9ydGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcG9seWdvbiBhcmVhIHVzaW5nIHJlZ2VvcyBjYWxjdWxhdGlvbgogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gICBhcmVhX3JnZW9zX2dBcmVhCiAgCiAgcHJpbnQoaSkKICB9IAp9CgojbG9vcCBmb3Igc291dGgKZm9yIChpIGluIDE6KGxlbmd0aCh3ZXN0X3BhY19zb3V0aF9sYXRpdHVkZXMpLTEpKSB7CiAgc291dGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X3BhY19zcGRmX21hc2tfZnVsbCksIHhtYXgod2VzdF9wYWNfc3BkZl9tYXNrX2Z1bGwpLCB3ZXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaSsxXSwgd2VzdF9wYWNfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKHdlc3RfcGFjX3NwZGZfbWFza19mdWxsLCBleHRlbnQoc291dGhfZXh0ZW50KSkKICAKICAjYWRkIGxhdGl0dWRlIGJpbiBpbmZvIHRvIGRhdGEgdGFibGUKICAgIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAibGF0aXR1ZGVfc3RhcnQiXSA8LSB3ZXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaV0KICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX2VuZCJdIDwtIHdlc3RfcGFjX3NvdXRoX2xhdGl0dWRlc1tpKzFdCiAgCiAgCiAgaWYoYWxsKGlzLm5hKHZhbHVlcyhzZWdtZW50X3NvdXRoKSkpKSB7ICNpZiB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgd2l0aGluIGEgYmluLCBtZWFuaW5nIHRoZXJlJ3Mgbm8gc2hlbGYgYXJlYSBhdCB0aGF0IGxhdGl0dWRlCiAgICAKICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICAgIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKICAKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9zb3V0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9zb3V0aCldCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKQogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfc291dGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X3NvdXRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X3NvdXRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfc291dGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggYXJlYSBvZiBwb2x5Z29uIGZyb20gcmFzdGVyOjphcmVhIGZ1bmN0aW9uCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfc291dGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIGZyb20gcmdlb3MgYXJlYSBjYWxjdWxhdGlvbiBmb3IgcHJvamVjdGVkIHBvbHlnb24KICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNjb21wYXJlIHJhc3RlcjphcmVhIGNhbGN1bGF0aW9uLCB0byBlcXVhbCBhcmVhIHN0aWxsIHVzaW5nIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbiwgdG8gcmdlb3M6OmdBcmVhIGZ1bmN0aW9uIGZvciBwb2x5Z29ucwoKZ2dwbG90KGRhdGEgPSB3ZXN0X3BhY19zaGVsZl9hcmVhcykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmdlb3NfZ0FyZWEpLCBjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yYXN0ZXJhcmVhKSwgY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfZXF1YWxhcmVhcHJvaiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjUpICsKICBsYWJzKHg9cGFzdGUwKCJMYXRpdHVkZSAiLCJcdTAwQjAiLCJFIiksIHkgPSAiQXJlYSBrbV4yIikgKwogIHRoZW1lX2NsYXNzaWMoKQoKY29yKHdlc3RfcGFjX3NoZWxmX2FyZWFzWywzOjVdLCB1c2UgPSAiY29tcGxldGUub2JzIikKCnNhdmUod2VzdF9wYWNfc2hlbGZfYXJlYXMsIGZpbGUgPSAid2VzdF9wYWNfc2hlbGZfYXJlYXNfMmRlZ3JlZXMuUmRhdGEiKQpsb2FkKCJ3ZXN0X3BhY19zaGVsZl9hcmVhc18yZGVncmVlcy5SZGF0YSIpCgpgYGAKCkNsYXNzaWZ5IGJ5IHBlcmNlbnQgY2hhbmdlISEKCmJldHdlZW4gMSBhbmQgSW5mICUgY2hhbmdlID0gYXQgbGVhc3QgMiBmb2xkIGluY3JlYXNlIChub3RlIEkgY2xhc3NpZmllZCBhbnkgY2hhbmdlIGZyb20gMCB0byBzb21ldGhpbmcgYXMgTk9UIGEgc2lnbmlmaWNhbnQgY2hhbmdlLCBzaG91bGQgcmV0dXJuIHRvIHRoaXMgY29uY2VwdHVhbGx5KQoKYmV0d2VlbiAtMC41IGFuZCAtaW5mICUgY2hhbmdlID0gYXQgbGVhc3QgMiBmb2xkIGRlY3JlYXNlCgpiZXR3ZWVuIC0wLjQ5OSBhbmQgMC45OTkgPSBubyBzaWduaWZpY2FudCBjaGFuZ2UgCgpGb3IgYXJlYSBtZXRyaWMgaGVyZSwgSSB1c2VkIHRoZSByYXN0ZXI6OmFyZWEgZnVuY3Rpb24gYXBwbGllZCB0byB0aGUgcHJvamVjdGVkIHNoYXBlZmlsZQpgYGB7ciBwZXJjZW50IHNoaWZ0IHdlc3Rlcm4gcGFjaWZpY30Kd2VzdF9wYWNfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9yYXN0ZXJhcmVhLWRhdGEudGFibGU6OnNoaWZ0KGFyZWFfcmFzdGVyYXJlYSwgdHlwZSA9ICJsYWciKSkvZGF0YS50YWJsZTo6c2hpZnQoYXJlYV9yYXN0ZXJhcmVhLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX3Jhc3RlcmFyZWEvMTAwMF0KCndlc3RfcGFjX3NoZWxmX2FyZWFzWyxoZW1pc3BoZXJlIDo9IGlmZWxzZShsYXRpdHVkZV9lbmQ+MCwibm9ydGgiLCJzb3V0aCIpXQoKd2VzdF9wYWNfc2hlbGZfYXJlYXNbLCBjaGFuZ2VfYWJvdmVfMmZvbGQgOj0gaWZlbHNlKChwZXJjZW50X2NoYW5nZT49MSAmIHBlcmNlbnRfY2hhbmdlPEluZiksIDEsIGlmZWxzZShwZXJjZW50X2NoYW5nZTw9LTAuNSwgLTEsIDApKV0KCndlc3RfcGFjX3NoZWxmX2FyZWFzX2hpZ2hsaWdodCA8LSB3ZXN0X3BhY19zaGVsZl9hcmVhc1tjaGFuZ2VfYWJvdmVfMmZvbGQgIT0gMCxdCgp3ZXN0X3BhY19zaGVsZl9hcmVhc19zdGF0cyA8LSB0YWJsZSh3ZXN0X3BhY19zaGVsZl9hcmVhc1ssLihjaGFuZ2VfYWJvdmVfMmZvbGQsaGVtaXNwaGVyZSldKQpgYGAKCk1vZGVsIGNoYW5nZSBmb3Igc291dGhlcm4gYW5kIG5vcnRoZXJuIGhlbWlzcGhlcmUKYGBge3IgbW9kZWwgbm9ydGhlcm4gdmVyc3VzIHNvdXRoZXJuIHdlc3Rlcm4gcGFjaWZpY30KI2FkZCBtaWQgbGF0aXR1ZGUKd2VzdF9wYWNfc2hlbGZfYXJlYXNbLGxhdGl0dWRlX21pZCA6PSBhYnMoKGxhdGl0dWRlX2VuZCtsYXRpdHVkZV9zdGFydCkvMildCgp3ZXN0X3BhY19ub3J0aF9tb2QgPC0gbG0oZGF0YSA9IHdlc3RfcGFjX3NoZWxmX2FyZWFzW2hlbWlzcGhlcmUgPT0gIm5vcnRoIl0sIGFyZWFfcmFzdGVyYXJlYSB+IGxhdGl0dWRlX21pZCkKc3VtbWFyeSh3ZXN0X3BhY19ub3J0aF9tb2QpCgp3ZXN0X3BhY19zb3V0aF9tb2QgPC0gbG0oZGF0YSA9IHdlc3RfcGFjX3NoZWxmX2FyZWFzW2hlbWlzcGhlcmUgPT0gInNvdXRoIl0sIGFyZWFfcmFzdGVyYXJlYSB+IGxhdGl0dWRlX21pZCkKc3VtbWFyeSh3ZXN0X3BhY19zb3V0aF9tb2QpCgpgYGAKCgpFYXN0ZXJuIFBhY2lmaWMKCmVhc3RfcGFjX3NwZGZfc2hpZnQKCmBgYHtyIHNwbGl0IHJhc3RlciBmb3IgZWFzdGVybiBwYWNpZmljfQpub3J0aF9leHRlbnQgPC0gYyh4bWluKGVhc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcyksIHhtYXgoZWFzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzKSwgMCwgeW1heChlYXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpKQpzb3V0aF9leHRlbnQgPC0gYyh4bWluKGVhc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcyksIHhtYXgoZWFzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzKSwgeW1pbihlYXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCAwKQoKI2Nyb3AgZWFzdF9wYWMgcmFzdGVyIGFib3ZlIGFuZCBiZWxvdyAwCmVhc3RfcGFjX3NwZGZfc2hpZnRfYWdnX25vcnRoIDwtIGNyb3AoZWFzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKCmVhc3RfcGFjX3NwZGZfc2hpZnRfYWdnX3NvdXRoIDwtIGNyb3AoZWFzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzLCBleHRlbnQoc291dGhfZXh0ZW50KSkKCiN1bmZvcnR1bmF0ZWx5LCBJIHRoaW5rIEkgbWF5IGhhdmUgdG8ganVzdCBkbyB0aGlzIG1hbnVhbGx5ICh1Z2x5LCBJIGtub3cpCgojYWxsIGNodW5rcyBmb3IgZWFzdCBwYWNpZmljCmVhc3RfcGFjX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heChlYXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCBieSA9IDIpCmVhc3RfcGFjX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbihlYXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCBieSA9IC0yKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCmVhc3RfcGFjX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKGVhc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgoZWFzdF9wYWNfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmVhc3RfcGFjX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgoZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCB4bWF4KGVhc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcyksIGVhc3RfcGFjX25vcnRoX2xhdGl0dWRlc1tpXSwgZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3AoZWFzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIGVhc3RfcGFjX25vcnRoX2xhdGl0dWRlc1tpXQogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSBlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgoZWFzdF9wYWNfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4oZWFzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzKSwgeG1heChlYXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCBlYXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaSsxXSwgZWFzdF9wYWNfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKGVhc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gZWFzdF9wYWNfc291dGhfbGF0aXR1ZGVzW2ldCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSBlYXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQoKICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICAgIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKICAKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9zb3V0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9zb3V0aCldCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKQogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfc291dGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X3NvdXRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X3NvdXRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfc291dGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggYXJlYSBvZiBwb2x5Z29uIGZyb20gcmFzdGVyOjphcmVhIGZ1bmN0aW9uCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfc291dGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIGZyb20gcmdlb3MgYXJlYSBjYWxjdWxhdGlvbiBmb3IgcHJvamVjdGVkIHBvbHlnb24KICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNjb21wYXJlIHJhc3RlcjphcmVhIGNhbGN1bGF0aW9uLCB0byBlcXVhbCBhcmVhIHN0aWxsIHVzaW5nIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbiwgdG8gcmdlb3M6OmdBcmVhIGZ1bmN0aW9uIGZvciBwb2x5Z29ucwoKZ2dwbG90KGRhdGEgPSBlYXN0X3BhY19zaGVsZl9hcmVhcykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmdlb3NfZ0FyZWEpLCBjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yYXN0ZXJhcmVhKSwgY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfZXF1YWxhcmVhcHJvaiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjUpICsKICBsYWJzKHg9cGFzdGUwKCJMYXRpdHVkZSAiLCJcdTAwQjAiLCJFIiksIHkgPSAiQXJlYSBrbV4yIikgKwogIHRoZW1lX2NsYXNzaWMoKQoKY29yKGVhc3RfcGFjX3NoZWxmX2FyZWFzWywzOjVdLCB1c2UgPSAiY29tcGxldGUub2JzIikKCnNhdmUoZWFzdF9wYWNfc2hlbGZfYXJlYXMsIGZpbGUgPSAiZWFzdF9wYWNfc2hlbGZfYXJlYXNfMmRlZ3JlZXMuUmRhdGEiKQoKYGBgCgpgYGB7ciBwZXJjZW50IHNoaWZ0IGVhc3Rlcm4gcGFjaWZpY30KZWFzdF9wYWNfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9yYXN0ZXJhcmVhLWRhdGEudGFibGU6OnNoaWZ0KGFyZWFfcmFzdGVyYXJlYSwgdHlwZSA9ICJsYWciKSkvZGF0YS50YWJsZTo6c2hpZnQoYXJlYV9yYXN0ZXJhcmVhLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX3Jhc3RlcmFyZWEvMTAwMF0KCmVhc3RfcGFjX3NoZWxmX2FyZWFzWyxoZW1pc3BoZXJlIDo9IGlmZWxzZShsYXRpdHVkZV9lbmQ+MCwibm9ydGgiLCJzb3V0aCIpXQoKZWFzdF9wYWNfc2hlbGZfYXJlYXNbLCBjaGFuZ2VfYWJvdmVfMmZvbGQgOj0gaWZlbHNlKChwZXJjZW50X2NoYW5nZT49MSAmIHBlcmNlbnRfY2hhbmdlPEluZiksIDEsIGlmZWxzZShwZXJjZW50X2NoYW5nZTw9LTAuNSwgLTEsIDApKV0KCmVhc3RfcGFjX3NoZWxmX2FyZWFzX2hpZ2hsaWdodCA8LSBlYXN0X3BhY19zaGVsZl9hcmVhc1tjaGFuZ2VfYWJvdmVfMmZvbGQgIT0gMCxdCgplYXN0X3BhY19zaGVsZl9hcmVhc19zdGF0cyA8LSB0YWJsZShlYXN0X3BhY19zaGVsZl9hcmVhc1ssLihjaGFuZ2VfYWJvdmVfMmZvbGQsIGhlbWlzcGhlcmUpXSkKYGBgCgpNb2RlbCBjaGFuZ2UgZm9yIHNvdXRoZXJuIGFuZCBub3J0aGVybiBoZW1pc3BoZXJlCmBgYHtyIG1vZGVsIG5vcnRoZXJuIHZlcnN1cyBzb3V0aGVybiBlYXN0ZXJuIHBhY2lmaWN9CiNhZGQgbWlkIGxhdGl0dWRlCmVhc3RfcGFjX3NoZWxmX2FyZWFzWyxsYXRpdHVkZV9taWQgOj0gYWJzKChsYXRpdHVkZV9lbmQrbGF0aXR1ZGVfc3RhcnQpLzIpXQoKZWFzdF9wYWNfbm9ydGhfbW9kIDwtIGxtKGRhdGEgPSBlYXN0X3BhY19zaGVsZl9hcmVhc1toZW1pc3BoZXJlID09ICJub3J0aCJdLCBhcmVhX3Jhc3RlcmFyZWEgfiBsYXRpdHVkZV9taWQpCnN1bW1hcnkoZWFzdF9wYWNfbm9ydGhfbW9kKQoKZWFzdF9wYWNfc291dGhfbW9kIDwtIGxtKGRhdGEgPSBlYXN0X3BhY19zaGVsZl9hcmVhc1toZW1pc3BoZXJlID09ICJzb3V0aCJdLCBhcmVhX3Jhc3RlcmFyZWEgfiBsYXRpdHVkZV9taWQpCnN1bW1hcnkoZWFzdF9wYWNfc291dGhfbW9kKQpgYGAKCldlc3Rlcm4gQXRsYW50aWMKCndlc3RfYXRsX3NwZGZfbWFzawoKYGBge3Igc3BsaXQgcmFzdGVyIGZvciB3ZXN0ZXJuIGF0bGFudGljfQpub3J0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfYXRsX3NwZGZfbWFza18xcyksIHhtYXgod2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgMCwgeW1heCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMpKQpzb3V0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfYXRsX3NwZGZfbWFza18xcyksIHhtYXgod2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgeW1pbih3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCAwKQoKI2Nyb3Agd2VzdF9hdGwgcmFzdGVyIGFib3ZlIGFuZCBiZWxvdyAwCndlc3RfYXRsX3NwZGZfc2hpZnRfYWdnX25vcnRoIDwtIGNyb3Aod2VzdF9hdGxfc3BkZl9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKCndlc3RfYXRsX3NwZGZfc2hpZnRfYWdnX3NvdXRoIDwtIGNyb3Aod2VzdF9hdGxfc3BkZl9tYXNrXzFzLCBleHRlbnQoc291dGhfZXh0ZW50KSkKCiN1bmZvcnR1bmF0ZWx5LCBJIHRoaW5rIEkgbWF5IGhhdmUgdG8ganVzdCBkbyB0aGlzIG1hbnVhbGx5ICh1Z2x5LCBJIGtub3cpCgojYWxsIGNodW5rcyBmb3Igd2VzdCBhdGxhbnRpYwp3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMgPC0gc2VxKDAsIHltYXgod2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgYnkgPSAyKQp3ZXN0X2F0bF9zb3V0aF9sYXRpdHVkZXMgPC0gc2VxKDAsIHltaW4od2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgYnkgPSAtMikKCiNzZXR1cCBkYXRhIHRhYmxlIHRvIHBvcHVsYXRlIGluIGxvb3AsIHN1YnRyYWN0aW5nIG9uZSB0byBhbGxvdyBmb3IgYmlucwp3ZXN0X2F0bF9zaGVsZl9hcmVhcyA8LSBhcy5kYXRhLnRhYmxlKG1hdHJpeChucm93ID0gKGxlbmd0aCh3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTErbGVuZ3RoKHdlc3RfYXRsX3NvdXRoX2xhdGl0dWRlcyktMSkpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAp3ZXN0X2F0bF9zaGVsZl9hcmVhc1ssIGxhdGl0dWRlX3N0YXJ0IDo9IGFzLm51bWVyaWMoVjEpXVssIGxhdGl0dWRlX2VuZCA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX3Jhc3RlcmFyZWEgOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9lcXVhbGFyZWFwcm9qIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmdlb3NfZ0FyZWEgOj0gYXMubnVtZXJpYyhWMSldWywgVjEgOj0gTlVMTF0KCiNsb29wIGZvciBub3J0aApmb3IgKGkgaW4gMToobGVuZ3RoKHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSkpIHsKICAjc2V0dGluZyB1cCBleHRlbnQgZm9yIHNsaWNpbmcgYnkgbWluIGFuZCBtYXggbG9uZ2l0dWRlcywgYW5kIGkgdG8gaSsxIGxhdGl0dWRlcwogIG5vcnRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCB3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXNbaV0sIHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlc1tpKzFdKQogIAogICNjcm9wIHJhc3RlciBzZWdlbWVudCBiYXNlZCBvbiBiaW4gZXh0ZW50CiAgc2VnbWVudF9ub3J0aCA8LSBjcm9wKHdlc3RfYXRsX3NwZGZfbWFza18xcywgZXh0ZW50KG5vcnRoX2V4dGVudCkpCiAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCBsYXRpdHVkaW5hbCBiaW4KICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAibGF0aXR1ZGVfc3RhcnQiXSA8LSB3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXNbaV0KICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAibGF0aXR1ZGVfZW5kIl0gPC0gd2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzW2krMV0KICAKICBpZihhbGwoaXMubmEodmFsdWVzKHNlZ21lbnRfbm9ydGgpKSkpIHsgI2lmIHRoZXJlJ3Mgbm8gc2hlbGYgYXJlYSB3aXRoaW4gYSBiaW4sIGFsbCBhcmVhID0gMAogICAgCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gMAogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gMAoKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsgI2lmIHRoZXJlIGlzIHNoZWxmIGFyZWEgd2l0aGluIHRoZSBiaW4sIGNhbGN1bGF0ZSBhcmVhIG9mIHNsaWNlCiAgCiAgICAjcmFzdGVyIGFyZWEgY2FsY3VsYXRpb24KICAgICAgI2dldCBzaXplcyBvZiBhbGwgY2VsbHMgaW4gcmFzdGVyIFtrbTJdCiAgICBjZWxsX3NpemVfcmFzdGVyPC1hcmVhKHNlZ21lbnRfbm9ydGgsIG5hLnJtPVRSVUUsIHdlaWdodHM9RkFMU0UpCiAgICAKICAgICNkZWxldGUgTkFzIGZyb20gdmVjdG9yIG9mIGFsbCByYXN0ZXIgY2VsbHMKICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWNlbGxfc2l6ZV9yYXN0ZXJbIWlzLm5hKHNlZ21lbnRfbm9ydGgpXQogICAgCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKSAjaW4ga21eMgogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSBzZWdtZW50X2FyZWFfcmFzdGVyCiAgICAKICAjY29udmVydCB0byBzcGF0aWFsIHBvbHlnb25zIHRvIGNoZWNrIGFyZWEgY2FsY3VsYXRpb25zCiAgICAKICAjY29udmVydCBzZWdtZW50IGZyb20gcmFzdGVyIHRvIHBvbHlnb24sIGVhY2ggY2VsbCBmcm9tIHRoZSByYXN0ZXIgaXMgYW4gaW5kZXBlbmRlbnQgcG9seWdvbiwgKGRpc3NvbHZlIG1lYW5zIGFsbCBjZWxscyB3aXRoIGEgdmFsdWUgb2YgMSBhcmUgYSBzaW5nbGUgcG9seWdvbiBpZiBjb25uZWN0ZWQpCiAgc2VnbWVudF9ub3J0aC5zcCA8LSByYXN0ZXJUb1BvbHlnb25zKHNlZ21lbnRfbm9ydGgsIGRpc3NvbHZlID0gVCkKICAKICAjICBJZiB4IGlzIGEgU3BhdGlhbFBvbHlnb25zKiBvYmplY3Q6IGFyZWEgb2YgZWFjaCBzcGF0aWFsIG9iamVjdCBpbiBzcXVhcmVkIG1ldGVycyBpZiB0aGUgQ1JTIGlzIGxvbmdpdHVkZS9sYXRpdHVkZSwgb3IgaW4gc3F1YXJlZCBtYXAgdW5pdHMgKHR5cGljYWxseSBtZXRlcikKICAKICAgICNwcm9qZWN0IHRvIGVxdWFsIGVhcnRoIGFyZWEgcHJvamVjdGlvbgogIHNlZ21lbnRfbm9ydGguc3AuRUEgPC0gc3BUcmFuc2Zvcm0oc2VnbWVudF9ub3J0aC5zcCwgQ1JTb2JqID0gZXF1YWxhcmVhcHJvamVjdGlvbikKCiAgI2NhbGN1bGF0ZSBhcmVhIG9mIHRoZSBzcGF0aWFsIG9iamVjdCBpbiBtXjIKICAgIHBvbHlnb25fc2l6ZS5zcCA8LSBhcmVhKHNlZ21lbnRfbm9ydGguc3AuRUEpCgogICAgI2NvbnZlcnQgZnJvbSBtXjIgdG8ga21eMgogICAgc2VnbWVudF9hcmVhX2VxdWFsYXJlYSA8LSBwb2x5Z29uX3NpemUuc3AvMWU2CgogICAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCBwb2x5Z29uIGFyZWEgdXNpbmcgcmFzdGVyIGNhbGN1bGF0aW9uCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEKICAKICAjYW5kIHRoZW4gcGxhaW4gYW5kIHNpbXBsZSBhbHNvIHVzaW5nIHJnZW9zOjpnQXJlYQogIAogIGFyZWFfcmdlb3NfZ0FyZWEgPC0gZ0FyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkvMWU2CiAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCBwb2x5Z29uIGFyZWEgdXNpbmcgcmVnZW9zIGNhbGN1bGF0aW9uCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNsb29wIGZvciBzb3V0aApmb3IgKGkgaW4gMToobGVuZ3RoKHdlc3RfYXRsX3NvdXRoX2xhdGl0dWRlcyktMSkpIHsKICBzb3V0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfYXRsX3NwZGZfbWFza18xcyksIHhtYXgod2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgd2VzdF9hdGxfc291dGhfbGF0aXR1ZGVzW2krMV0sIHdlc3RfYXRsX3NvdXRoX2xhdGl0dWRlc1tpXSkgI29yZGVyPSB4bWluLCB4bWF4LCB5bWluLCB5bWF4KQogIAogICNyYXN0ZXIgc2VnbWVudAogIHNlZ21lbnRfc291dGggPC0gY3JvcCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMsIGV4dGVudChzb3V0aF9leHRlbnQpKQogIAogICNhZGQgbGF0aXR1ZGUgYmluIGluZm8gdG8gZGF0YSB0YWJsZQogICAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9zdGFydCJdIDwtIHdlc3RfYXRsX3NvdXRoX2xhdGl0dWRlc1tpXQogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAibGF0aXR1ZGVfZW5kIl0gPC0gd2VzdF9hdGxfc291dGhfbGF0aXR1ZGVzW2krMV0KICAKICAKICBpZihhbGwoaXMubmEodmFsdWVzKHNlZ21lbnRfc291dGgpKSkpIHsgI2lmIHRoZXJlJ3Mgbm8gc2hlbGYgYXJlYSB3aXRoaW4gYSBiaW4sIG1lYW5pbmcgdGhlcmUncyBubyBzaGVsZiBhcmVhIGF0IHRoYXQgbGF0aXR1ZGUKCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSAwCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCiAgCiAgcHJpbnQoaSkKICAgIAogIH0gZWxzZSB7CiAgCiAgICAjcmFzdGVyIGFyZWEgY2FsY3VsYXRpb24KICAgICAgI2dldCBzaXplcyBvZiBhbGwgY2VsbHMgaW4gcmFzdGVyIFtrbTJdCiAgICBjZWxsX3NpemVfcmFzdGVyPC1hcmVhKHNlZ21lbnRfc291dGgsIG5hLnJtPVRSVUUsIHdlaWdodHM9RkFMU0UpCiAgICAKICAgICNkZWxldGUgTkFzIGZyb20gdmVjdG9yIG9mIGFsbCByYXN0ZXIgY2VsbHMKICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWNlbGxfc2l6ZV9yYXN0ZXJbIWlzLm5hKHNlZ21lbnRfc291dGgpXQogICAgI2NvbXB1dGUgYXJlYSBvZiBhbGwgY2VsbHMgaW4gZ2VvX3Jhc3RlcgogICAgI2Z1bGwgYXJlYSAgICAgICAgICA8LSB0b3RhbCAjIGdyaWQgY2VsbHMgICAgICogbWVkaWFuIGNlbGwgYXJlYSAodXNpbmcgbWVkaWFuIGNhcmVzIGxlc3MgYWJvdXQgZXh0cmVtZSB2YWx1ZXMpCiAgICBzZWdtZW50X2FyZWFfcmFzdGVyIDwtIGxlbmd0aChjZWxsX3NpemVfcmFzdGVyKSptZWRpYW4oY2VsbF9zaXplX3Jhc3RlcikKICAgIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcmFzdGVyIGFyZWEKICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X3NvdXRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9zb3V0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9zb3V0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X3NvdXRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9zb3V0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGFyZWEgb2YgcG9seWdvbiBmcm9tIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbgogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSBmcm9tIHJnZW9zIGFyZWEgY2FsY3VsYXRpb24gZm9yIHByb2plY3RlZCBwb2x5Z29uCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gICBhcmVhX3JnZW9zX2dBcmVhCiAgCiAgcHJpbnQoaSkKICB9IAp9CgojY29tcGFyZSByYXN0ZXI6YXJlYSBjYWxjdWxhdGlvbiwgdG8gZXF1YWwgYXJlYSBzdGlsbCB1c2luZyByYXN0ZXI6OmFyZWEgZnVuY3Rpb24sIHRvIHJnZW9zOjpnQXJlYSBmdW5jdGlvbiBmb3IgcG9seWdvbnMKCmdncGxvdChkYXRhID0gd2VzdF9hdGxfc2hlbGZfYXJlYXMpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIHkgPSBhcmVhX3JnZW9zX2dBcmVhKSwgY29sb3IgPSAicHVycGxlIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmFzdGVyYXJlYSksIGNvbG9yID0gImRhcmtncmVlbiIsIHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIHkgPSBhcmVhX2VxdWFsYXJlYXByb2opLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMC41KSArCiAgbGFicyh4PXBhc3RlMCgiTGF0aXR1ZGUgIiwiXHUwMEIwIiwiRSIpLCB5ID0gIkFyZWEga21eMiIpICsKICB0aGVtZV9jbGFzc2ljKCkKCmNvcih3ZXN0X2F0bF9zaGVsZl9hcmVhc1ssMzo1XSwgdXNlID0gImNvbXBsZXRlLm9icyIpCgpgYGAKCmBgYHtyIHBlcmNlbnQgc2hpZnQgd2VzdGVybiBhdGxhbnRpY30Kd2VzdF9hdGxfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9yYXN0ZXJhcmVhLWRhdGEudGFibGU6OnNoaWZ0KGFyZWFfcmFzdGVyYXJlYSwgdHlwZSA9ICJsYWciKSkvZGF0YS50YWJsZTo6c2hpZnQoYXJlYV9yYXN0ZXJhcmVhLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX3Jhc3RlcmFyZWEvMTAwMF0KCndlc3RfYXRsX3NoZWxmX2FyZWFzWyxoZW1pc3BoZXJlIDo9IGlmZWxzZShsYXRpdHVkZV9lbmQ+MCwibm9ydGgiLCJzb3V0aCIpXQoKd2VzdF9hdGxfc2hlbGZfYXJlYXNbLCBjaGFuZ2VfYWJvdmVfMmZvbGQgOj0gaWZlbHNlKChwZXJjZW50X2NoYW5nZT49MSAmIHBlcmNlbnRfY2hhbmdlPEluZiksIDEsIGlmZWxzZShwZXJjZW50X2NoYW5nZTw9LTAuNSwgLTEsIDApKV0KCndlc3RfYXRsX3NoZWxmX2FyZWFzX2hpZ2hsaWdodCA8LSB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tjaGFuZ2VfYWJvdmVfMmZvbGQgIT0gMCxdCgp3ZXN0X2F0bF9zaGVsZl9hcmVhc19zdGF0cyA8LSB0YWJsZSh3ZXN0X2F0bF9zaGVsZl9hcmVhc1ssLihjaGFuZ2VfYWJvdmVfMmZvbGQsIGhlbWlzcGhlcmUpXSkKYGBgCgpNb2RlbCBjaGFuZ2UgZm9yIHNvdXRoZXJuIGFuZCBub3J0aGVybiBoZW1pc3BoZXJlCmBgYHtyIG1vZGVsIG5vcnRoZXJuIHZlcnN1cyBzb3V0aGVybiB3ZXN0ZXJuIGF0bGFudGljfQojYWRkIG1pZCBsYXRpdHVkZQp3ZXN0X2F0bF9zaGVsZl9hcmVhc1ssbGF0aXR1ZGVfbWlkIDo9IGFicygobGF0aXR1ZGVfZW5kK2xhdGl0dWRlX3N0YXJ0KS8yKV0KCndlc3RfYXRsX25vcnRoX21vZCA8LSBsbShkYXRhID0gd2VzdF9hdGxfc2hlbGZfYXJlYXNbaGVtaXNwaGVyZSA9PSAibm9ydGgiXSwgYXJlYV9yYXN0ZXJhcmVhIH4gbGF0aXR1ZGVfbWlkKQpzdW1tYXJ5KHdlc3RfYXRsX25vcnRoX21vZCkKCndlc3RfYXRsX3NvdXRoX21vZCA8LSBsbShkYXRhID0gd2VzdF9hdGxfc2hlbGZfYXJlYXNbaGVtaXNwaGVyZSA9PSAic291dGgiXSwgYXJlYV9yYXN0ZXJhcmVhIH4gbGF0aXR1ZGVfbWlkKQpzdW1tYXJ5KHdlc3RfYXRsX3NvdXRoX21vZCkKYGBgCgpFYXN0ZXJuIEF0bGFudGljCgplYXN0X2F0bF9zcGRmX25vYnVmX21hc2sKCmBgYHtyIHNwbGl0IHJhc3RlciBmb3IgZWFzdGVybiBhdGxhbnRpY30Kbm9ydGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCB4bWF4KGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcyksIDAsIHltYXgoZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzKSkKc291dGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCB4bWF4KGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcyksIHltaW4oZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzKSwgMCkKCiNjcm9wIGVhc3RfYXRsIHJhc3RlciBhYm92ZSBhbmQgYmVsb3cgMAplYXN0X2F0bF9zcGRmX3NoaWZ0X2FnZ19ub3J0aCA8LSBjcm9wKGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcywgZXh0ZW50KG5vcnRoX2V4dGVudCkpCgplYXN0X2F0bF9zcGRmX3NoaWZ0X2FnZ19zb3V0aCA8LSBjcm9wKGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCgojdW5mb3J0dW5hdGVseSwgSSB0aGluayBJIG1heSBoYXZlIHRvIGp1c3QgZG8gdGhpcyBtYW51YWxseSAodWdseSwgSSBrbm93KQoKI2FsbCBjaHVua3MgZm9yIGVhc3QgYXRsYW50aWMKZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzIDwtIHNlcSgwLCB5bWF4KGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcyksIGJ5ID0gMikKZWFzdF9hdGxfc291dGhfbGF0aXR1ZGVzIDwtIHNlcSgwLCB5bWluKGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcyksIGJ5ID0gLTIpCgojc2V0dXAgZGF0YSB0YWJsZSB0byBwb3B1bGF0ZSBpbiBsb29wLCBzdWJ0cmFjdGluZyBvbmUgdG8gYWxsb3cgZm9yIGJpbnMKZWFzdF9hdGxfc2hlbGZfYXJlYXMgPC0gYXMuZGF0YS50YWJsZShtYXRyaXgobnJvdyA9IChsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xK2xlbmd0aChlYXN0X2F0bF9zb3V0aF9sYXRpdHVkZXMpLTEpKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKZWFzdF9hdGxfc2hlbGZfYXJlYXNbLCBsYXRpdHVkZV9zdGFydCA6PSBhcy5udW1lcmljKFYxKV1bLCBsYXRpdHVkZV9lbmQgOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yYXN0ZXJhcmVhIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfZXF1YWxhcmVhcHJvaiA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX3JnZW9zX2dBcmVhIDo9IGFzLm51bWVyaWMoVjEpXVssIFYxIDo9IE5VTExdCgojbG9vcCBmb3Igbm9ydGgKZm9yIChpIGluIDE6KGxlbmd0aChlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpKSB7CiAgI3NldHRpbmcgdXAgZXh0ZW50IGZvciBzbGljaW5nIGJ5IG1pbiBhbmQgbWF4IGxvbmdpdHVkZXMsIGFuZCBpIHRvIGkrMSBsYXRpdHVkZXMKICBub3J0aF9leHRlbnQgPC0gYyh4bWluKGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcyksIHhtYXgoZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzKSwgZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzW2ldLCBlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXNbaSsxXSkKICAKICAjY3JvcCByYXN0ZXIgc2VnZW1lbnQgYmFzZWQgb24gYmluIGV4dGVudAogIHNlZ21lbnRfbm9ydGggPC0gY3JvcChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMsIGV4dGVudChub3J0aF9leHRlbnQpKQogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggbGF0aXR1ZGluYWwgYmluCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzW2ldCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImxhdGl0dWRlX2VuZCJdIDwtIGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlc1tpKzFdCiAgCiAgaWYoYWxsKGlzLm5hKHZhbHVlcyhzZWdtZW50X25vcnRoKSkpKSB7ICNpZiB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgd2l0aGluIGEgYmluLCBhbGwgYXJlYSA9IDAKICAgIAogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSAwCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKCiAgCiAgcHJpbnQoaSkKICAgIAogIH0gZWxzZSB7ICNpZiB0aGVyZSBpcyBzaGVsZiBhcmVhIHdpdGhpbiB0aGUgYmluLCBjYWxjdWxhdGUgYXJlYSBvZiBzbGljZQogIAogICAgI3Jhc3RlciBhcmVhIGNhbGN1bGF0aW9uCiAgICAgICNnZXQgc2l6ZXMgb2YgYWxsIGNlbGxzIGluIHJhc3RlciBba20yXQogICAgY2VsbF9zaXplX3Jhc3RlcjwtYXJlYShzZWdtZW50X25vcnRoLCBuYS5ybT1UUlVFLCB3ZWlnaHRzPUZBTFNFKQogICAgCiAgICAjZGVsZXRlIE5BcyBmcm9tIHZlY3RvciBvZiBhbGwgcmFzdGVyIGNlbGxzCiAgICBjZWxsX3NpemVfcmFzdGVyPC1jZWxsX3NpemVfcmFzdGVyWyFpcy5uYShzZWdtZW50X25vcnRoKV0KICAgIAogICAgI2NvbXB1dGUgYXJlYSBvZiBhbGwgY2VsbHMgaW4gZ2VvX3Jhc3RlcgogICAgI2Z1bGwgYXJlYSAgICAgICAgICA8LSB0b3RhbCAjIGdyaWQgY2VsbHMgICAgICogbWVkaWFuIGNlbGwgYXJlYSAodXNpbmcgbWVkaWFuIGNhcmVzIGxlc3MgYWJvdXQgZXh0cmVtZSB2YWx1ZXMpCiAgICBzZWdtZW50X2FyZWFfcmFzdGVyIDwtIGxlbmd0aChjZWxsX3NpemVfcmFzdGVyKSptZWRpYW4oY2VsbF9zaXplX3Jhc3RlcikgI2luIGttXjIKICAgIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcmFzdGVyIGFyZWEKICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfbm9ydGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X25vcnRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X25vcnRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfbm9ydGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X25vcnRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcG9seWdvbiBhcmVhIHVzaW5nIHJhc3RlciBjYWxjdWxhdGlvbgogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfbm9ydGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcG9seWdvbiBhcmVhIHVzaW5nIHJlZ2VvcyBjYWxjdWxhdGlvbgogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gICBhcmVhX3JnZW9zX2dBcmVhCiAgCiAgcHJpbnQoaSkKICB9IAp9CgojbG9vcCBmb3Igc291dGgKZm9yIChpIGluIDE6KGxlbmd0aChlYXN0X2F0bF9zb3V0aF9sYXRpdHVkZXMpLTEpKSB7CiAgc291dGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCB4bWF4KGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcyksIGVhc3RfYXRsX3NvdXRoX2xhdGl0dWRlc1tpKzFdLCBlYXN0X2F0bF9zb3V0aF9sYXRpdHVkZXNbaV0pICNvcmRlcj0geG1pbiwgeG1heCwgeW1pbiwgeW1heCkKICAKICAjcmFzdGVyIHNlZ21lbnQKICBzZWdtZW50X3NvdXRoIDwtIGNyb3AoZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzLCBleHRlbnQoc291dGhfZXh0ZW50KSkKICAKICAjYWRkIGxhdGl0dWRlIGJpbiBpbmZvIHRvIGRhdGEgdGFibGUKICAgIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAibGF0aXR1ZGVfc3RhcnQiXSA8LSBlYXN0X2F0bF9zb3V0aF9sYXRpdHVkZXNbaV0KICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX2VuZCJdIDwtIGVhc3RfYXRsX3NvdXRoX2xhdGl0dWRlc1tpKzFdCiAgCiAgCiAgaWYoYWxsKGlzLm5hKHZhbHVlcyhzZWdtZW50X3NvdXRoKSkpKSB7ICNpZiB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgd2l0aGluIGEgYmluLCBtZWFuaW5nIHRoZXJlJ3Mgbm8gc2hlbGYgYXJlYSBhdCB0aGF0IGxhdGl0dWRlCgogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gMAogICAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gMAogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgewogIAogICAgI3Jhc3RlciBhcmVhIGNhbGN1bGF0aW9uCiAgICAgICNnZXQgc2l6ZXMgb2YgYWxsIGNlbGxzIGluIHJhc3RlciBba20yXQogICAgY2VsbF9zaXplX3Jhc3RlcjwtYXJlYShzZWdtZW50X3NvdXRoLCBuYS5ybT1UUlVFLCB3ZWlnaHRzPUZBTFNFKQogICAgCiAgICAjZGVsZXRlIE5BcyBmcm9tIHZlY3RvciBvZiBhbGwgcmFzdGVyIGNlbGxzCiAgICBjZWxsX3NpemVfcmFzdGVyPC1jZWxsX3NpemVfcmFzdGVyWyFpcy5uYShzZWdtZW50X3NvdXRoKV0KICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSBzZWdtZW50X2FyZWFfcmFzdGVyCiAgICAKICAKICAjY29udmVydCB0byBzcGF0aWFsIHBvbHlnb25zIHRvIGNoZWNrIGFyZWEgY2FsY3VsYXRpb25zCiAgICAKICAjY29udmVydCBzZWdtZW50IGZyb20gcmFzdGVyIHRvIHBvbHlnb24sIGVhY2ggY2VsbCBmcm9tIHRoZSByYXN0ZXIgaXMgYW4gaW5kZXBlbmRlbnQgcG9seWdvbiwgKGRpc3NvbHZlIG1lYW5zIGFsbCBjZWxscyB3aXRoIGEgdmFsdWUgb2YgMSBhcmUgYSBzaW5nbGUgcG9seWdvbiBpZiBjb25uZWN0ZWQpCiAgc2VnbWVudF9zb3V0aC5zcCA8LSByYXN0ZXJUb1BvbHlnb25zKHNlZ21lbnRfc291dGgsIGRpc3NvbHZlID0gVCkKICAKICAjICBJZiB4IGlzIGEgU3BhdGlhbFBvbHlnb25zKiBvYmplY3Q6IGFyZWEgb2YgZWFjaCBzcGF0aWFsIG9iamVjdCBpbiBzcXVhcmVkIG1ldGVycyBpZiB0aGUgQ1JTIGlzIGxvbmdpdHVkZS9sYXRpdHVkZSwgb3IgaW4gc3F1YXJlZCBtYXAgdW5pdHMgKHR5cGljYWxseSBtZXRlcikKICAKICAgICNwcm9qZWN0IHRvIGVxdWFsIGVhcnRoIGFyZWEgcHJvamVjdGlvbgogIHNlZ21lbnRfc291dGguc3AuRUEgPC0gc3BUcmFuc2Zvcm0oc2VnbWVudF9zb3V0aC5zcCwgQ1JTb2JqID0gZXF1YWxhcmVhcHJvamVjdGlvbikKCiAgI2NhbGN1bGF0ZSBhcmVhIG9mIHRoZSBzcGF0aWFsIG9iamVjdCBpbiBtXjIKICAgIHBvbHlnb25fc2l6ZS5zcCA8LSBhcmVhKHNlZ21lbnRfc291dGguc3AuRUEpCgogICAgI2NvbnZlcnQgZnJvbSBtXjIgdG8ga21eMgogICAgc2VnbWVudF9hcmVhX2VxdWFsYXJlYSA8LSBwb2x5Z29uX3NpemUuc3AvMWU2CgogICAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCBhcmVhIG9mIHBvbHlnb24gZnJvbSByYXN0ZXI6OmFyZWEgZnVuY3Rpb24KICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEKICAKICAjYW5kIHRoZW4gcGxhaW4gYW5kIHNpbXBsZSBhbHNvIHVzaW5nIHJnZW9zOjpnQXJlYQogIAogIGFyZWFfcmdlb3NfZ0FyZWEgPC0gZ0FyZWEoc2VnbWVudF9zb3V0aC5zcC5FQSkvMWU2CiAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgZnJvbSByZ2VvcyBhcmVhIGNhbGN1bGF0aW9uIGZvciBwcm9qZWN0ZWQgcG9seWdvbgogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2NvbXBhcmUgcmFzdGVyOmFyZWEgY2FsY3VsYXRpb24sIHRvIGVxdWFsIGFyZWEgc3RpbGwgdXNpbmcgcmFzdGVyOjphcmVhIGZ1bmN0aW9uLCB0byByZ2Vvczo6Z0FyZWEgZnVuY3Rpb24gZm9yIHBvbHlnb25zCgpnZ3Bsb3QoZGF0YSA9IGVhc3RfYXRsX3NoZWxmX2FyZWFzKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yZ2Vvc19nQXJlYSksIGNvbG9yID0gInB1cnBsZSIsIHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIHkgPSBhcmVhX3Jhc3RlcmFyZWEpLCBjb2xvciA9ICJkYXJrZ3JlZW4iLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9lcXVhbGFyZWFwcm9qKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDAuNSkgKwogIGxhYnMoeD1wYXN0ZTAoIkxhdGl0dWRlICIsIlx1MDBCMCIsIkUiKSwgeSA9ICJBcmVhIGttXjIiKSArCiAgdGhlbWVfY2xhc3NpYygpCgpjb3IoZWFzdF9hdGxfc2hlbGZfYXJlYXNbLDM6NV0sIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQoKYGBgCgpgYGB7ciBwZXJjZW50IHNoaWZ0IGVhc3Rlcm4gYXRsYW50aWN9CmVhc3RfYXRsX3NoZWxmX2FyZWFzWywgcGVyY2VudF9jaGFuZ2UgOj0gKGFyZWFfcmFzdGVyYXJlYS1kYXRhLnRhYmxlOjpzaGlmdChhcmVhX3Jhc3RlcmFyZWEsIHR5cGUgPSAibGFnIikpL2RhdGEudGFibGU6OnNoaWZ0KGFyZWFfcmFzdGVyYXJlYSwgdHlwZSA9ICJsYWciKV1bLGFyZWFfMTAwMHMgOj0gYXJlYV9yYXN0ZXJhcmVhLzEwMDBdCgplYXN0X2F0bF9zaGVsZl9hcmVhc1ssaGVtaXNwaGVyZSA6PSBpZmVsc2UobGF0aXR1ZGVfZW5kPjAsIm5vcnRoIiwic291dGgiKV0KCmVhc3RfYXRsX3NoZWxmX2FyZWFzWywgY2hhbmdlX2Fib3ZlXzJmb2xkIDo9IGlmZWxzZSgocGVyY2VudF9jaGFuZ2U+PTEgJiBwZXJjZW50X2NoYW5nZTxJbmYpLCAxLCBpZmVsc2UocGVyY2VudF9jaGFuZ2U8PS0wLjUsIC0xLCAwKSldCgplYXN0X2F0bF9zaGVsZl9hcmVhc19oaWdobGlnaHQgPC0gZWFzdF9hdGxfc2hlbGZfYXJlYXNbY2hhbmdlX2Fib3ZlXzJmb2xkICE9IDAsXQoKZWFzdF9hdGxfc2hlbGZfYXJlYXNfc3RhdHMgPC0gdGFibGUoZWFzdF9hdGxfc2hlbGZfYXJlYXNbLC4oY2hhbmdlX2Fib3ZlXzJmb2xkLCBoZW1pc3BoZXJlKV0pCmBgYAoKTW9kZWwgY2hhbmdlIGZvciBzb3V0aGVybiBhbmQgbm9ydGhlcm4gaGVtaXNwaGVyZQpgYGB7ciBtb2RlbCBub3J0aGVybiB2ZXJzdXMgc291dGhlcm4gZWFzdGVybiBhdGxhbnRpY30KI2FkZCBtaWQgbGF0aXR1ZGUKZWFzdF9hdGxfc2hlbGZfYXJlYXNbLGxhdGl0dWRlX21pZCA6PSBhYnMoKGxhdGl0dWRlX2VuZCtsYXRpdHVkZV9zdGFydCkvMildCgplYXN0X2F0bF9ub3J0aF9tb2QgPC0gbG0oZGF0YSA9IGVhc3RfYXRsX3NoZWxmX2FyZWFzW2hlbWlzcGhlcmUgPT0gIm5vcnRoIl0sIGFyZWFfcmFzdGVyYXJlYSB+IGxhdGl0dWRlX21pZCkKc3VtbWFyeShlYXN0X2F0bF9ub3J0aF9tb2QpCgplYXN0X2F0bF9zb3V0aF9tb2QgPC0gbG0oZGF0YSA9IGVhc3RfYXRsX3NoZWxmX2FyZWFzW2hlbWlzcGhlcmUgPT0gInNvdXRoIl0sIGFyZWFfcmFzdGVyYXJlYSB+IGxhdGl0dWRlX21pZCkKc3VtbWFyeShlYXN0X2F0bF9zb3V0aF9tb2QpCmBgYAoKV2VzdGVybiBJbmRpYW4KCndlc3RfaW5kX3NwZGZfbWFzawoKYGBge3Igc3BsaXQgcmFzdGVyIGZvciB3ZXN0ZXJuIGluZGlhbn0Kbm9ydGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIDAsIHltYXgod2VzdF9pbmRfc3BkZl9tYXNrXzFzKSkKc291dGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIHltaW4od2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgMCkKCiNjcm9wIHdlc3RfaW5kIHJhc3RlciBhYm92ZSBhbmQgYmVsb3cgMAp3ZXN0X2luZF9zcGRmX3NoaWZ0X2FnZ19ub3J0aCA8LSBjcm9wKHdlc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KG5vcnRoX2V4dGVudCkpCgp3ZXN0X2luZF9zcGRmX3NoaWZ0X2FnZ19zb3V0aCA8LSBjcm9wKHdlc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCgojdW5mb3J0dW5hdGVseSwgSSB0aGluayBJIG1heSBoYXZlIHRvIGp1c3QgZG8gdGhpcyBtYW51YWxseSAodWdseSwgSSBrbm93KQoKI2FsbCBjaHVua3MgZm9yIHdlc3QgaW5kaWFuCndlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heCh3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCBieSA9IDIpCndlc3RfaW5kX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCBieSA9IC0yKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCndlc3RfaW5kX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgod2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCndlc3RfaW5kX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlc1tpXSwgd2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3Aod2VzdF9pbmRfc3BkZl9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlc1tpXQogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X2luZF9ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB3ZXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaSsxXSwgd2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKHdlc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gd2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzW2ldCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQoKICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICAgIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKICAKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9zb3V0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9zb3V0aCldCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKQogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfc291dGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X3NvdXRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X3NvdXRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfc291dGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggYXJlYSBvZiBwb2x5Z29uIGZyb20gcmFzdGVyOjphcmVhIGZ1bmN0aW9uCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfc291dGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIGZyb20gcmdlb3MgYXJlYSBjYWxjdWxhdGlvbiBmb3IgcHJvamVjdGVkIHBvbHlnb24KICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNjb21wYXJlIHJhc3RlcjphcmVhIGNhbGN1bGF0aW9uLCB0byBlcXVhbCBhcmVhIHN0aWxsIHVzaW5nIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbiwgdG8gcmdlb3M6OmdBcmVhIGZ1bmN0aW9uIGZvciBwb2x5Z29ucwoKZ2dwbG90KGRhdGEgPSB3ZXN0X2luZF9zaGVsZl9hcmVhcykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmdlb3NfZ0FyZWEpLCBjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yYXN0ZXJhcmVhKSwgY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfZXF1YWxhcmVhcHJvaiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjUpICsKICBsYWJzKHg9cGFzdGUwKCJMYXRpdHVkZSAiLCJcdTAwQjAiLCJFIiksIHkgPSAiQXJlYSBrbV4yIikgKwogIHRoZW1lX2NsYXNzaWMoKQoKY29yKHdlc3RfaW5kX3NoZWxmX2FyZWFzWywzOjVdLCB1c2UgPSAiY29tcGxldGUub2JzIikKYGBgCgpgYGB7ciBwZXJjZW50IHNoaWZ0IHdlc3Rlcm4gaW5kaWFufQp3ZXN0X2luZF9zaGVsZl9hcmVhc1ssIHBlcmNlbnRfY2hhbmdlIDo9IChhcmVhX3Jhc3RlcmFyZWEtZGF0YS50YWJsZTo6c2hpZnQoYXJlYV9yYXN0ZXJhcmVhLCB0eXBlID0gImxhZyIpKS9kYXRhLnRhYmxlOjpzaGlmdChhcmVhX3Jhc3RlcmFyZWEsIHR5cGUgPSAibGFnIildWyxhcmVhXzEwMDBzIDo9IGFyZWFfcmFzdGVyYXJlYS8xMDAwXQoKd2VzdF9pbmRfc2hlbGZfYXJlYXNbLGhlbWlzcGhlcmUgOj0gaWZlbHNlKGxhdGl0dWRlX2VuZD4wLCJub3J0aCIsInNvdXRoIildCgp3ZXN0X2luZF9zaGVsZl9hcmVhc1ssIGNoYW5nZV9hYm92ZV8yZm9sZCA6PSBpZmVsc2UoKHBlcmNlbnRfY2hhbmdlPj0xICYgcGVyY2VudF9jaGFuZ2U8SW5mKSwgMSwgaWZlbHNlKHBlcmNlbnRfY2hhbmdlPD0tMC41LCAtMSwgMCkpXQoKd2VzdF9pbmRfc2hlbGZfYXJlYXNfaGlnaGxpZ2h0IDwtIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2NoYW5nZV9hYm92ZV8yZm9sZCAhPSAwLF0KCndlc3RfaW5kX3NoZWxmX2FyZWFzX3N0YXRzIDwtIHRhYmxlKHdlc3RfaW5kX3NoZWxmX2FyZWFzWywuKGNoYW5nZV9hYm92ZV8yZm9sZCwgaGVtaXNwaGVyZSldKQpgYGAKCk1vZGVsIGNoYW5nZSBmb3Igc291dGhlcm4gYW5kIG5vcnRoZXJuIGhlbWlzcGhlcmUKYGBge3IgbW9kZWwgbm9ydGhlcm4gdmVyc3VzIHNvdXRoZXJuIHdlc3Rlcm4gaW5kaWFufQojYWRkIG1pZCBsYXRpdHVkZQp3ZXN0X2luZF9zaGVsZl9hcmVhc1ssbGF0aXR1ZGVfbWlkIDo9IGFicygobGF0aXR1ZGVfZW5kK2xhdGl0dWRlX3N0YXJ0KS8yKV0KCndlc3RfaW5kX25vcnRoX21vZCA8LSBsbShkYXRhID0gd2VzdF9pbmRfc2hlbGZfYXJlYXNbaGVtaXNwaGVyZSA9PSAibm9ydGgiXSwgYXJlYV9yYXN0ZXJhcmVhIH4gbGF0aXR1ZGVfbWlkKQpzdW1tYXJ5KHdlc3RfaW5kX25vcnRoX21vZCkKCndlc3RfaW5kX3NvdXRoX21vZCA8LSBsbShkYXRhID0gd2VzdF9pbmRfc2hlbGZfYXJlYXNbaGVtaXNwaGVyZSA9PSAic291dGgiXSwgYXJlYV9yYXN0ZXJhcmVhIH4gbGF0aXR1ZGVfbWlkKQpzdW1tYXJ5KHdlc3RfaW5kX3NvdXRoX21vZCkKYGBgCgpFYXN0ZXJuIEluZGlhbgoKZWFzdF9pbmRfc3BkZl9tYXNrXzFzCgpgYGB7ciBzcGxpdCByYXN0ZXIgZm9yIGVhc3Rlcm4gaW5kaWFufQpub3J0aF9leHRlbnQgPC0gYyh4bWluKGVhc3RfaW5kX3NwZGZfbWFza18xcyksIHhtYXgoZWFzdF9pbmRfc3BkZl9tYXNrXzFzKSwgMCwgeW1heChlYXN0X2luZF9zcGRmX21hc2tfMXMpKQpzb3V0aF9leHRlbnQgPC0gYyh4bWluKGVhc3RfaW5kX3NwZGZfbWFza18xcyksIHhtYXgoZWFzdF9pbmRfc3BkZl9tYXNrXzFzKSwgeW1pbihlYXN0X2luZF9zcGRmX21hc2tfMXMpLCAwKQoKI2Nyb3AgZWFzdF9pbmQgcmFzdGVyIGFib3ZlIGFuZCBiZWxvdyAwCmVhc3RfaW5kX3NwZGZfc2hpZnRfYWdnX25vcnRoIDwtIGNyb3AoZWFzdF9pbmRfc3BkZl9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKCmVhc3RfaW5kX3NwZGZfc2hpZnRfYWdnX3NvdXRoIDwtIGNyb3AoZWFzdF9pbmRfc3BkZl9tYXNrXzFzLCBleHRlbnQoc291dGhfZXh0ZW50KSkKCiN1bmZvcnR1bmF0ZWx5LCBJIHRoaW5rIEkgbWF5IGhhdmUgdG8ganVzdCBkbyB0aGlzIG1hbnVhbGx5ICh1Z2x5LCBJIGtub3cpCgojYWxsIGNodW5rcyBmb3IgZWFzdCBpbmRpYW4KZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzIDwtIHNlcSgwLCB5bWF4KGVhc3RfaW5kX3NwZGZfbWFza18xcyksIGJ5ID0gMikKZWFzdF9pbmRfc291dGhfbGF0aXR1ZGVzIDwtIHNlcSgwLCB5bWluKGVhc3RfaW5kX3NwZGZfbWFza18xcyksIGJ5ID0gLTIpCgojc2V0dXAgZGF0YSB0YWJsZSB0byBwb3B1bGF0ZSBpbiBsb29wLCBzdWJ0cmFjdGluZyBvbmUgdG8gYWxsb3cgZm9yIGJpbnMKZWFzdF9pbmRfc2hlbGZfYXJlYXMgPC0gYXMuZGF0YS50YWJsZShtYXRyaXgobnJvdyA9IChsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xK2xlbmd0aChlYXN0X2luZF9zb3V0aF9sYXRpdHVkZXMpLTEpKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKZWFzdF9pbmRfc2hlbGZfYXJlYXNbLCBsYXRpdHVkZV9zdGFydCA6PSBhcy5udW1lcmljKFYxKV1bLCBsYXRpdHVkZV9lbmQgOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yYXN0ZXJhcmVhIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfZXF1YWxhcmVhcHJvaiA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX3JnZW9zX2dBcmVhIDo9IGFzLm51bWVyaWMoVjEpXVssIFYxIDo9IE5VTExdCgojbG9vcCBmb3Igbm9ydGgKZm9yIChpIGluIDE6KGxlbmd0aChlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpKSB7CiAgI3NldHRpbmcgdXAgZXh0ZW50IGZvciBzbGljaW5nIGJ5IG1pbiBhbmQgbWF4IGxvbmdpdHVkZXMsIGFuZCBpIHRvIGkrMSBsYXRpdHVkZXMKICBub3J0aF9leHRlbnQgPC0gYyh4bWluKGVhc3RfaW5kX3NwZGZfbWFza18xcyksIHhtYXgoZWFzdF9pbmRfc3BkZl9tYXNrXzFzKSwgZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzW2ldLCBlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXNbaSsxXSkKICAKICAjY3JvcCByYXN0ZXIgc2VnZW1lbnQgYmFzZWQgb24gYmluIGV4dGVudAogIHNlZ21lbnRfbm9ydGggPC0gY3JvcChlYXN0X2luZF9zcGRmX21hc2tfMXMsIGV4dGVudChub3J0aF9leHRlbnQpKQogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggbGF0aXR1ZGluYWwgYmluCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzW2ldCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImxhdGl0dWRlX2VuZCJdIDwtIGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlc1tpKzFdCiAgCiAgaWYoYWxsKGlzLm5hKHZhbHVlcyhzZWdtZW50X25vcnRoKSkpKSB7ICNpZiB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgd2l0aGluIGEgYmluLCBhbGwgYXJlYSA9IDAKICAgIAogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSAwCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKCiAgCiAgcHJpbnQoaSkKICAgIAogIH0gZWxzZSB7ICNpZiB0aGVyZSBpcyBzaGVsZiBhcmVhIHdpdGhpbiB0aGUgYmluLCBjYWxjdWxhdGUgYXJlYSBvZiBzbGljZQogIAogICAgI3Jhc3RlciBhcmVhIGNhbGN1bGF0aW9uCiAgICAgICNnZXQgc2l6ZXMgb2YgYWxsIGNlbGxzIGluIHJhc3RlciBba20yXQogICAgY2VsbF9zaXplX3Jhc3RlcjwtYXJlYShzZWdtZW50X25vcnRoLCBuYS5ybT1UUlVFLCB3ZWlnaHRzPUZBTFNFKQogICAgCiAgICAjZGVsZXRlIE5BcyBmcm9tIHZlY3RvciBvZiBhbGwgcmFzdGVyIGNlbGxzCiAgICBjZWxsX3NpemVfcmFzdGVyPC1jZWxsX3NpemVfcmFzdGVyWyFpcy5uYShzZWdtZW50X25vcnRoKV0KICAgIAogICAgI2NvbXB1dGUgYXJlYSBvZiBhbGwgY2VsbHMgaW4gZ2VvX3Jhc3RlcgogICAgI2Z1bGwgYXJlYSAgICAgICAgICA8LSB0b3RhbCAjIGdyaWQgY2VsbHMgICAgICogbWVkaWFuIGNlbGwgYXJlYSAodXNpbmcgbWVkaWFuIGNhcmVzIGxlc3MgYWJvdXQgZXh0cmVtZSB2YWx1ZXMpCiAgICBzZWdtZW50X2FyZWFfcmFzdGVyIDwtIGxlbmd0aChjZWxsX3NpemVfcmFzdGVyKSptZWRpYW4oY2VsbF9zaXplX3Jhc3RlcikgI2luIGttXjIKICAgIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcmFzdGVyIGFyZWEKICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfbm9ydGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X25vcnRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X25vcnRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfbm9ydGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X25vcnRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcG9seWdvbiBhcmVhIHVzaW5nIHJhc3RlciBjYWxjdWxhdGlvbgogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfbm9ydGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcG9seWdvbiBhcmVhIHVzaW5nIHJlZ2VvcyBjYWxjdWxhdGlvbgogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gICBhcmVhX3JnZW9zX2dBcmVhCiAgCiAgcHJpbnQoaSkKICB9IAp9CgojbG9vcCBmb3Igc291dGgKZm9yIChpIGluIDE6KGxlbmd0aChlYXN0X2luZF9zb3V0aF9sYXRpdHVkZXMpLTEpKSB7CiAgc291dGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KGVhc3RfaW5kX3NwZGZfbWFza18xcyksIGVhc3RfaW5kX3NvdXRoX2xhdGl0dWRlc1tpKzFdLCBlYXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaV0pICNvcmRlcj0geG1pbiwgeG1heCwgeW1pbiwgeW1heCkKICAKICAjcmFzdGVyIHNlZ21lbnQKICBzZWdtZW50X3NvdXRoIDwtIGNyb3AoZWFzdF9pbmRfc3BkZl9tYXNrXzFzLCBleHRlbnQoc291dGhfZXh0ZW50KSkKICAKICAjYWRkIGxhdGl0dWRlIGJpbiBpbmZvIHRvIGRhdGEgdGFibGUKICAgIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAibGF0aXR1ZGVfc3RhcnQiXSA8LSBlYXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaV0KICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX2VuZCJdIDwtIGVhc3RfaW5kX3NvdXRoX2xhdGl0dWRlc1tpKzFdCiAgCiAgCiAgaWYoYWxsKGlzLm5hKHZhbHVlcyhzZWdtZW50X3NvdXRoKSkpKSB7ICNpZiB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgd2l0aGluIGEgYmluLCBtZWFuaW5nIHRoZXJlJ3Mgbm8gc2hlbGYgYXJlYSBhdCB0aGF0IGxhdGl0dWRlCgogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gMAogICAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gMAogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgewogIAogICAgI3Jhc3RlciBhcmVhIGNhbGN1bGF0aW9uCiAgICAgICNnZXQgc2l6ZXMgb2YgYWxsIGNlbGxzIGluIHJhc3RlciBba20yXQogICAgY2VsbF9zaXplX3Jhc3RlcjwtYXJlYShzZWdtZW50X3NvdXRoLCBuYS5ybT1UUlVFLCB3ZWlnaHRzPUZBTFNFKQogICAgCiAgICAjZGVsZXRlIE5BcyBmcm9tIHZlY3RvciBvZiBhbGwgcmFzdGVyIGNlbGxzCiAgICBjZWxsX3NpemVfcmFzdGVyPC1jZWxsX3NpemVfcmFzdGVyWyFpcy5uYShzZWdtZW50X3NvdXRoKV0KICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSBzZWdtZW50X2FyZWFfcmFzdGVyCiAgICAKICAKICAjY29udmVydCB0byBzcGF0aWFsIHBvbHlnb25zIHRvIGNoZWNrIGFyZWEgY2FsY3VsYXRpb25zCiAgICAKICAjY29udmVydCBzZWdtZW50IGZyb20gcmFzdGVyIHRvIHBvbHlnb24sIGVhY2ggY2VsbCBmcm9tIHRoZSByYXN0ZXIgaXMgYW4gaW5kZXBlbmRlbnQgcG9seWdvbiwgKGRpc3NvbHZlIG1lYW5zIGFsbCBjZWxscyB3aXRoIGEgdmFsdWUgb2YgMSBhcmUgYSBzaW5nbGUgcG9seWdvbiBpZiBjb25uZWN0ZWQpCiAgc2VnbWVudF9zb3V0aC5zcCA8LSByYXN0ZXJUb1BvbHlnb25zKHNlZ21lbnRfc291dGgsIGRpc3NvbHZlID0gVCkKICAKICAjICBJZiB4IGlzIGEgU3BhdGlhbFBvbHlnb25zKiBvYmplY3Q6IGFyZWEgb2YgZWFjaCBzcGF0aWFsIG9iamVjdCBpbiBzcXVhcmVkIG1ldGVycyBpZiB0aGUgQ1JTIGlzIGxvbmdpdHVkZS9sYXRpdHVkZSwgb3IgaW4gc3F1YXJlZCBtYXAgdW5pdHMgKHR5cGljYWxseSBtZXRlcikKICAKICAgICNwcm9qZWN0IHRvIGVxdWFsIGVhcnRoIGFyZWEgcHJvamVjdGlvbgogIHNlZ21lbnRfc291dGguc3AuRUEgPC0gc3BUcmFuc2Zvcm0oc2VnbWVudF9zb3V0aC5zcCwgQ1JTb2JqID0gZXF1YWxhcmVhcHJvamVjdGlvbikKCiAgI2NhbGN1bGF0ZSBhcmVhIG9mIHRoZSBzcGF0aWFsIG9iamVjdCBpbiBtXjIKICAgIHBvbHlnb25fc2l6ZS5zcCA8LSBhcmVhKHNlZ21lbnRfc291dGguc3AuRUEpCgogICAgI2NvbnZlcnQgZnJvbSBtXjIgdG8ga21eMgogICAgc2VnbWVudF9hcmVhX2VxdWFsYXJlYSA8LSBwb2x5Z29uX3NpemUuc3AvMWU2CgogICAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCBhcmVhIG9mIHBvbHlnb24gZnJvbSByYXN0ZXI6OmFyZWEgZnVuY3Rpb24KICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEKICAKICAjYW5kIHRoZW4gcGxhaW4gYW5kIHNpbXBsZSBhbHNvIHVzaW5nIHJnZW9zOjpnQXJlYQogIAogIGFyZWFfcmdlb3NfZ0FyZWEgPC0gZ0FyZWEoc2VnbWVudF9zb3V0aC5zcC5FQSkvMWU2CiAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgZnJvbSByZ2VvcyBhcmVhIGNhbGN1bGF0aW9uIGZvciBwcm9qZWN0ZWQgcG9seWdvbgogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2NvbXBhcmUgcmFzdGVyOmFyZWEgY2FsY3VsYXRpb24sIHRvIGVxdWFsIGFyZWEgc3RpbGwgdXNpbmcgcmFzdGVyOjphcmVhIGZ1bmN0aW9uLCB0byByZ2Vvczo6Z0FyZWEgZnVuY3Rpb24gZm9yIHBvbHlnb25zCgpnZ3Bsb3QoZGF0YSA9IGVhc3RfaW5kX3NoZWxmX2FyZWFzKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yZ2Vvc19nQXJlYSksIGNvbG9yID0gInB1cnBsZSIsIHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIHkgPSBhcmVhX3Jhc3RlcmFyZWEpLCBjb2xvciA9ICJkYXJrZ3JlZW4iLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9lcXVhbGFyZWFwcm9qKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDAuNSkgKwogIGxhYnMoeD1wYXN0ZTAoIkxhdGl0dWRlICIsIlx1MDBCMCIsIkUiKSwgeSA9ICJBcmVhIGttXjIiKSArCiAgdGhlbWVfY2xhc3NpYygpCgpjb3IoZWFzdF9pbmRfc2hlbGZfYXJlYXNbLDM6NV0sIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQoKYGBgCgpgYGB7ciBwZXJjZW50IHNoaWZ0IGVhc3Rlcm4gaW5kaWFufQplYXN0X2luZF9zaGVsZl9hcmVhc1ssIHBlcmNlbnRfY2hhbmdlIDo9IChhcmVhX3Jhc3RlcmFyZWEtZGF0YS50YWJsZTo6c2hpZnQoYXJlYV9yYXN0ZXJhcmVhLCB0eXBlID0gImxhZyIpKS9kYXRhLnRhYmxlOjpzaGlmdChhcmVhX3Jhc3RlcmFyZWEsIHR5cGUgPSAibGFnIildWyxhcmVhXzEwMDBzIDo9IGFyZWFfcmFzdGVyYXJlYS8xMDAwXQoKZWFzdF9pbmRfc2hlbGZfYXJlYXNbLGhlbWlzcGhlcmUgOj0gaWZlbHNlKGxhdGl0dWRlX2VuZD4wLCJub3J0aCIsInNvdXRoIildCgplYXN0X2luZF9zaGVsZl9hcmVhc1ssIGNoYW5nZV9hYm92ZV8yZm9sZCA6PSBpZmVsc2UoKHBlcmNlbnRfY2hhbmdlPj0xICYgcGVyY2VudF9jaGFuZ2U8SW5mKSwgMSwgaWZlbHNlKHBlcmNlbnRfY2hhbmdlPD0tMC41LCAtMSwgMCkpXQoKZWFzdF9pbmRfc2hlbGZfYXJlYXNfaGlnaGxpZ2h0IDwtIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2NoYW5nZV9hYm92ZV8yZm9sZCAhPSAwLF0KCmVhc3RfaW5kX3NoZWxmX2FyZWFzX3N0YXRzIDwtIHRhYmxlKGVhc3RfaW5kX3NoZWxmX2FyZWFzWywuKGNoYW5nZV9hYm92ZV8yZm9sZCxoZW1pc3BoZXJlKV0pCmBgYAoKTW9kZWwgY2hhbmdlIGZvciBzb3V0aGVybiBhbmQgbm9ydGhlcm4gaGVtaXNwaGVyZQpgYGB7ciBtb2RlbCBub3J0aGVybiB2ZXJzdXMgc291dGhlcm4gZWFzdGVybiBpbmRpYW59CiNhZGQgbWlkIGxhdGl0dWRlCmVhc3RfaW5kX3NoZWxmX2FyZWFzWyxsYXRpdHVkZV9taWQgOj0gYWJzKChsYXRpdHVkZV9lbmQrbGF0aXR1ZGVfc3RhcnQpLzIpXQoKZWFzdF9pbmRfbm9ydGhfbW9kIDwtIGxtKGRhdGEgPSBlYXN0X2luZF9zaGVsZl9hcmVhc1toZW1pc3BoZXJlID09ICJub3J0aCJdLCBhcmVhX3Jhc3RlcmFyZWEgfiBsYXRpdHVkZV9taWQpCnN1bW1hcnkoZWFzdF9pbmRfbm9ydGhfbW9kKQoKZWFzdF9pbmRfc291dGhfbW9kIDwtIGxtKGRhdGEgPSBlYXN0X2luZF9zaGVsZl9hcmVhc1toZW1pc3BoZXJlID09ICJzb3V0aCJdLCBhcmVhX3Jhc3RlcmFyZWEgfiBsYXRpdHVkZV9taWQpCnN1bW1hcnkoZWFzdF9pbmRfc291dGhfbW9kKQpgYGAKCgpQbG90cyBvZiBsYXRpdHVkZSB2ZXJzdXMgaGFiaXRhdCBhdmFpbGFiaWxpdHkKCkluY2x1ZGUgdHJlbmQgbGluZXMgb25seSBmb3IgdGhvc2Ugd2l0aCBzaWduaWZpY2FudCBjb2VmZmljaWVudHMgYmV0d2VlbiBsYXRpdHVkZSBzdGFydCBhbmQgYXJlYV4yCk5PVDoKLSBFYXN0IEluZGlhbiBTb3V0aGVybiBhbmQgTm9ydGhlcm4KLSBFYXN0IFBhY2lmaWMgU291dGhlcm4KLSBXZXN0IEluZGlhbiBTb3V0aGVybgoKYGBge3IgcGxvdHMgbGF0aXR1ZGUgaGFiaXRhdCBhdmFpbGFiaWxpdHl9CiMjZWFzdCBpbmRpYW4KI3NpbXVsYXRlIGRhdGEgdG8gcGxvdCB0cmVuZGxpbmUKZWFzdF9pbmRfbm9ydGhfZGF0YSA8LSBkYXRhLnRhYmxlKGxhdGl0dWRlX21pZCA9IHVuaXF1ZShlYXN0X2luZF9zaGVsZl9hcmVhc1tsYXRpdHVkZV9lbmQ+MCxdJGxhdGl0dWRlX21pZCkpCgplYXN0X2luZF9ub3J0aF9kYXRhWyxhcmVhXzEwMDBzIDo9IGVhc3RfaW5kX25vcnRoX21vZCRjb2VmZmljaWVudHNbWzFdXS8xMDAwK2Vhc3RfaW5kX25vcnRoX21vZCRjb2VmZmljaWVudHNbWzJdXS8xMDAwKmxhdGl0dWRlX21pZF0KCmVhc3RfaW5kX3NvdXRoX2RhdGEgPC0gZGF0YS50YWJsZShsYXRpdHVkZV9taWQgPSB1bmlxdWUoZWFzdF9pbmRfc2hlbGZfYXJlYXNbbGF0aXR1ZGVfZW5kIDwwLF0kbGF0aXR1ZGVfbWlkKSkKCmVhc3RfaW5kX3NvdXRoX2RhdGFbLGFyZWFfMTAwMHMgOj0gZWFzdF9pbmRfc291dGhfbW9kJGNvZWZmaWNpZW50c1tbMV1dLzEwMDArZWFzdF9pbmRfc291dGhfbW9kJGNvZWZmaWNpZW50c1tbMl1dLzEwMDAqbGF0aXR1ZGVfbWlkXQoKI2Vhc3QgaW5kaWFuCihhcmVhX2xhdGl0dWRlX2Vhc3RfaW5kICA8LSBnZ3Bsb3QoKSArCiMgIGdlb21fbGluZShkYXRhID0gZWFzdF9pbmRfbm9ydGhfZGF0YSwgYWVzKHg9bGF0aXR1ZGVfbWlkLCB5ID0gYXJlYV8xMDAwcyksIGNvbG9yID0gImdyYXk2MCIsIHNpemUgPSAwLjgsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKyBub3Qgc2lnbmlmaWNhbnQKIyAgZ2VvbV9saW5lKGRhdGEgPSBlYXN0X2luZF9zb3V0aF9kYXRhLCBhZXMoeD1sYXRpdHVkZV9taWQsIHkgPSBhcmVhXzEwMDBzKSwgY29sb3IgPSAiZ3JheTYwIiwgc2l6ZSA9IDAuOCwgbGluZXR5cGUgPSAibG9uZ2Rhc2giKSArIG5vdCBzaWduaWZpY2FudAogIGdlb21fcG9pbnQoZGF0YSA9IGVhc3RfaW5kX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSwgc2hhcGUgPTE4LCBzaXplID0gMC43KSArCiAgZ2VvbV9saW5lKGRhdGEgPSBlYXN0X2luZF9zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcyksIHNpemUgPSAwLjcpICsKICBnZW9tX3J1ZyhkYXRhID0gZWFzdF9pbmRfc2hlbGZfYXJlYXNfaGlnaGxpZ2h0LCBhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCBjb2xvciA9IGFzLmZhY3RvcihjaGFuZ2VfYWJvdmVfMmZvbGQpKSkgKwogbGFicyh4PXBhc3RlMCgiTGF0aXR1ZGUgIiwiXHUwMEIwIiwiRSIpLCB5ID0gZXhwcmVzc2lvbihwYXN0ZSgiQXJlYSAoMTAwMHMgb2YgIiwga21eezJ9LCIpIikpKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKG9wdGlvbiA9ICJBIiwgYmVnaW4gPSAwLjMsIGVuZCA9IDAuNywgbmFtZSA9ICJBc3NvY2lhdGVkIENoYW5nZVxuaW4gU2hlbGYgQXJlYSIsIGxhYmVscyA9IGMoIkNvbnRyYWN0aW9uIiwgIkV4cGFuc2lvbiIpKSArCiAgIyNhbm5vdGF0ZSgidGV4dCIsIHggPTIyLCB5ID0gNzAwMDAsIGxhYmVsID0gIkVhc3Rlcm4gSW5kaWFuIE9jZWFuIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICB4bGltKG1pbihlYXN0X2luZF9zaGVsZl9hcmVhcyRsYXRpdHVkZV9lbmQpLCBtYXgoZWFzdF9pbmRfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbigxMCwgNDAsIDEwLCAxMCkpKQoKCiAgZ2dzYXZlKGFyZWFfbGF0aXR1ZGVfZWFzdF9pbmQsIGZpbGVuYW1lID0gImFyZWFfbGF0aXR1ZGVfZWFzdF9pbmRfMmRlZ3JlZXMuanBnIiwgaGVpZ2h0ID0gNCwgdW5pdHMgPSBjKCJpbiIpKQogIAojI3dlc3QgaW5kaWFuCndlc3RfaW5kX25vcnRoX2RhdGEgPC0gZGF0YS50YWJsZShsYXRpdHVkZV9taWQgPSB1bmlxdWUod2VzdF9pbmRfc2hlbGZfYXJlYXNbbGF0aXR1ZGVfZW5kPjAsXSRsYXRpdHVkZV9taWQpKQoKd2VzdF9pbmRfbm9ydGhfZGF0YVssYXJlYV8xMDAwcyA6PSB3ZXN0X2luZF9ub3J0aF9tb2QkY29lZmZpY2llbnRzW1sxXV0vMTAwMCt3ZXN0X2luZF9ub3J0aF9tb2QkY29lZmZpY2llbnRzW1syXV0vMTAwMCpsYXRpdHVkZV9taWRdCgp3ZXN0X2luZF9zb3V0aF9kYXRhIDwtIGRhdGEudGFibGUobGF0aXR1ZGVfbWlkID0gdW5pcXVlKHdlc3RfaW5kX3NoZWxmX2FyZWFzW2xhdGl0dWRlX2VuZCA8MCxdJGxhdGl0dWRlX21pZCkpCgp3ZXN0X2luZF9zb3V0aF9kYXRhWyxhcmVhXzEwMDBzIDo9IHdlc3RfaW5kX3NvdXRoX21vZCRjb2VmZmljaWVudHNbWzFdXS8xMDAwK3dlc3RfaW5kX3NvdXRoX21vZCRjb2VmZmljaWVudHNbWzJdXS8xMDAwKmxhdGl0dWRlX21pZF0KCihhcmVhX2xhdGl0dWRlX3dlc3RfaW5kICA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSB3ZXN0X2luZF9ub3J0aF9kYXRhLCBhZXMoeD1sYXRpdHVkZV9taWQsIHkgPSBhcmVhXzEwMDBzKSwgY29sb3IgPSAiZ3JheTYwIiwgc2l6ZSA9IDAuOCwgbGluZXR5cGUgPSAibG9uZ2Rhc2giKSArCiAjIGdlb21fbGluZShkYXRhID0gd2VzdF9pbmRfc291dGhfZGF0YSwgYWVzKHg9bGF0aXR1ZGVfbWlkLCB5ID0gYXJlYV8xMDAwcyksIGNvbG9yID0gImdyYXk2MCIsIHNpemUgPSAwLjgsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKyBub3Qgc2lnbmlmaWNhbnQKICBnZW9tX3BvaW50KGRhdGEgPSB3ZXN0X2luZF9zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcyksIHNoYXBlID0xOCwgc2l6ZSA9IDAuNykgKyAKICBnZW9tX2xpbmUoZGF0YSA9IHdlc3RfaW5kX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSwgc2l6ZSA9IDAuNykgKwogICAgZ2VvbV9ydWcoZGF0YSA9IHdlc3RfaW5kX3NoZWxmX2FyZWFzX2hpZ2hsaWdodCwgYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgY29sb3IgPSBhcy5mYWN0b3IoY2hhbmdlX2Fib3ZlXzJmb2xkKSkpICsKIGxhYnMoeD1wYXN0ZTAoIkxhdGl0dWRlICIsIlx1MDBCMCIsIkUiKSwgeSA9IGV4cHJlc3Npb24ocGFzdGUoIkFyZWEgKDEwMDBzIG9mICIsIGttXnsyfSwiKSIpKSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChvcHRpb24gPSAiQSIsIGJlZ2luID0gMC4zLCBlbmQgPSAwLjcsIG5hbWUgPSAiQXNzb2NpYXRlZCBDaGFuZ2VcbmluIFNoZWxmIEFyZWEiLCBsYWJlbHMgPSBjKCJDb250cmFjdGlvbiIsICJFeHBhbnNpb24iKSkgKwogICNhbm5vdGF0ZSgidGV4dCIsIHggPSAzMCwgeSA9IDMzMDAwLCBsYWJlbCA9ICJXZXN0ZXJuIEluZGlhbiBPY2VhbiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgeGxpbShtaW4od2VzdF9pbmRfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSwgbWF4KHdlc3RfaW5kX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDQwLCAxMCwgMTApKSkKCiAgZ2dzYXZlKGFyZWFfbGF0aXR1ZGVfd2VzdF9pbmQsIGZpbGVuYW1lID0gImFyZWFfbGF0aXR1ZGVfd2VzdF9pbmRfMmRlZ3JlZXMuanBnIiwgaGVpZ2h0ID0gNCwgdW5pdHMgPSBjKCJpbiIpKQoKd2VzdF9hdGxfbm9ydGhfZGF0YSA8LSBkYXRhLnRhYmxlKGxhdGl0dWRlX21pZCA9IHVuaXF1ZSh3ZXN0X2F0bF9zaGVsZl9hcmVhc1tsYXRpdHVkZV9lbmQ+MCxdJGxhdGl0dWRlX21pZCkpCgp3ZXN0X2F0bF9ub3J0aF9kYXRhWyxhcmVhXzEwMDBzIDo9IHdlc3RfYXRsX25vcnRoX21vZCRjb2VmZmljaWVudHNbWzFdXS8xMDAwK3dlc3RfYXRsX25vcnRoX21vZCRjb2VmZmljaWVudHNbWzJdXS8xMDAwKmxhdGl0dWRlX21pZF0KCndlc3RfYXRsX3NvdXRoX2RhdGEgPC0gZGF0YS50YWJsZShsYXRpdHVkZV9taWQgPSB1bmlxdWUod2VzdF9hdGxfc2hlbGZfYXJlYXNbbGF0aXR1ZGVfZW5kIDwwLF0kbGF0aXR1ZGVfbWlkKSkKCndlc3RfYXRsX3NvdXRoX2RhdGFbLGFyZWFfMTAwMHMgOj0gd2VzdF9hdGxfc291dGhfbW9kJGNvZWZmaWNpZW50c1tbMV1dLzEwMDArd2VzdF9hdGxfc291dGhfbW9kJGNvZWZmaWNpZW50c1tbMl1dLzEwMDAqbGF0aXR1ZGVfbWlkXQoKYXJlYV9sYXRpdHVkZV93ZXN0X2F0bCAgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gd2VzdF9hdGxfbm9ydGhfZGF0YSwgYWVzKHg9bGF0aXR1ZGVfbWlkLCB5ID0gYXJlYV8xMDAwcyksIGNvbG9yID0gImdyYXk2MCIsIHNpemUgPSAwLjgsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKwogIGdlb21fbGluZShkYXRhID0gd2VzdF9hdGxfc291dGhfZGF0YSwgYWVzKHg9LWxhdGl0dWRlX21pZCwgeSA9IGFyZWFfMTAwMHMpLCBjb2xvciA9ICJncmF5NjAiLCBzaXplID0gMC44LCBsaW5ldHlwZSA9ICJsb25nZGFzaCIpICsKICBnZW9tX3BvaW50KGRhdGEgPSB3ZXN0X2F0bF9zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcyksIHNoYXBlID0xOCwgc2l6ZSA9IDAuNykgKyAKICBnZW9tX2xpbmUoZGF0YSA9IHdlc3RfYXRsX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSwgc2l6ZSA9IDAuNykgKwogIGdlb21fcnVnKGRhdGEgPSB3ZXN0X2F0bF9zaGVsZl9hcmVhc19oaWdobGlnaHQsIGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIGNvbG9yID0gYXMuZmFjdG9yKGNoYW5nZV9hYm92ZV8yZm9sZCkpKSArCiBsYWJzKHg9cGFzdGUwKCJMYXRpdHVkZSAiLCJcdTAwQjAiLCJFIiksIHkgPSBleHByZXNzaW9uKHBhc3RlKCJBcmVhICgxMDAwcyBvZiAiLCBrbV57Mn0sIikiKSkpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2Qob3B0aW9uID0gIkEiLCBiZWdpbiA9IDAuMywgZW5kID0gMC43LCBuYW1lID0gIkFzc29jaWF0ZWQgQ2hhbmdlXG5pbiBTaGVsZiBBcmVhIiwgbGFiZWxzID0gYygiQ29udHJhY3Rpb24iLCAiRXhwYW5zaW9uIikpICsKICAjYW5ub3RhdGUoInRleHQiLCB4ID0gODAsIHkgPSAxMjAwMDAsIGxhYmVsID0gIldlc3Rlcm4gQXRsYW50aWMgT2NlYW4iKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIHhsaW0obWluKHdlc3RfYXRsX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCksIG1heCh3ZXN0X2F0bF9zaGVsZl9hcmVhcyRsYXRpdHVkZV9lbmQpKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDEwLCA0MCwgMTAsIDEwKSkKCiAgZ2dzYXZlKGFyZWFfbGF0aXR1ZGVfd2VzdF9hdGwsIGZpbGVuYW1lID0gImFyZWFfbGF0aXR1ZGVfd2VzdF9hdGxfMmRlZ3JlZXMuanBnIiwgaGVpZ2h0ID0gNCwgdW5pdHMgPSBjKCJpbiIpKQoKICAKZWFzdF9hdGxfbm9ydGhfZGF0YSA8LSBkYXRhLnRhYmxlKGxhdGl0dWRlX21pZCA9IHVuaXF1ZShlYXN0X2F0bF9zaGVsZl9hcmVhc1tsYXRpdHVkZV9lbmQ+MCxdJGxhdGl0dWRlX21pZCkpCgplYXN0X2F0bF9ub3J0aF9kYXRhWyxhcmVhXzEwMDBzIDo9IGVhc3RfYXRsX25vcnRoX21vZCRjb2VmZmljaWVudHNbWzFdXS8xMDAwK2Vhc3RfYXRsX25vcnRoX21vZCRjb2VmZmljaWVudHNbWzJdXS8xMDAwKmxhdGl0dWRlX21pZF0KCmVhc3RfYXRsX3NvdXRoX2RhdGEgPC0gZGF0YS50YWJsZShsYXRpdHVkZV9taWQgPSB1bmlxdWUoZWFzdF9hdGxfc2hlbGZfYXJlYXNbbGF0aXR1ZGVfZW5kIDwwLF0kbGF0aXR1ZGVfbWlkKSkKCmVhc3RfYXRsX3NvdXRoX2RhdGFbLGFyZWFfMTAwMHMgOj0gZWFzdF9hdGxfc291dGhfbW9kJGNvZWZmaWNpZW50c1tbMV1dLzEwMDArZWFzdF9hdGxfc291dGhfbW9kJGNvZWZmaWNpZW50c1tbMl1dLzEwMDAqbGF0aXR1ZGVfbWlkXSAgCgphcmVhX2xhdGl0dWRlX2Vhc3RfYXRsICA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBlYXN0X2F0bF9ub3J0aF9kYXRhLCBhZXMoeD1sYXRpdHVkZV9taWQsIHkgPSBhcmVhXzEwMDBzKSwgY29sb3IgPSAiZ3JheTYwIiwgc2l6ZSA9IDAuOCwgbGluZXR5cGUgPSAibG9uZ2Rhc2giKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBlYXN0X2F0bF9zb3V0aF9kYXRhLCBhZXMoeD0tbGF0aXR1ZGVfbWlkLCB5ID0gYXJlYV8xMDAwcyksIGNvbG9yID0gImdyYXk2MCIsIHNpemUgPSAwLjgsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGVhc3RfYXRsX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSwgc2hhcGUgPTE4LCBzaXplID0gMC43KSArIAogIGdlb21fbGluZShkYXRhID0gZWFzdF9hdGxfc2hlbGZfYXJlYXMsIGFlcyh4PWxhdGl0dWRlX3N0YXJ0LCB5PWFyZWFfMTAwMHMpLCBzaXplID0gMC43KSArCiAgZ2VvbV9ydWcoZGF0YSA9IGVhc3RfYXRsX3NoZWxmX2FyZWFzX2hpZ2hsaWdodCwgYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgY29sb3IgPSBhcy5mYWN0b3IoY2hhbmdlX2Fib3ZlXzJmb2xkKSkpICsKIGxhYnMoeD1wYXN0ZTAoIkxhdGl0dWRlICIsIlx1MDBCMCIsIkUiKSwgeSA9IGV4cHJlc3Npb24ocGFzdGUoIkFyZWEgKDEwMDBzIG9mICIsIGttXnsyfSwiKSIpKSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChvcHRpb24gPSAiQSIsIGJlZ2luID0gMC4zLCBlbmQgPSAwLjcsIG5hbWUgPSAiQXNzb2NpYXRlZCBDaGFuZ2VcbmluIFNoZWxmIEFyZWEiLCBsYWJlbHMgPSBjKCJDb250cmFjdGlvbiIsICJFeHBhbnNpb24iKSkgKwogICNhbm5vdGF0ZSgidGV4dCIsIHggPSA4Mi41LCB5ID0gMTEwMDAwLCBsYWJlbCA9ICJFYXN0ZXJuIEF0bGFudGljIE9jZWFuIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICB4bGltKG1pbihlYXN0X2F0bF9zaGVsZl9hcmVhcyRsYXRpdHVkZV9lbmQpLCBtYXgoZWFzdF9hdGxfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbigxMCwgNDAsIDEwLCAxMCkpCgogIGdnc2F2ZShhcmVhX2xhdGl0dWRlX2Vhc3RfYXRsLCBmaWxlbmFtZSA9ICJhcmVhX2xhdGl0dWRlX2Vhc3RfYXRsXzJkZWdyZWVzLmpwZyIsIGhlaWdodCA9IDQsIHVuaXRzID0gYygiaW4iKSkKICAKICAKZWFzdF9wYWNfbm9ydGhfZGF0YSA8LSBkYXRhLnRhYmxlKGxhdGl0dWRlX21pZCA9IHVuaXF1ZShlYXN0X3BhY19zaGVsZl9hcmVhc1tsYXRpdHVkZV9lbmQ+MCxdJGxhdGl0dWRlX21pZCkpCgplYXN0X3BhY19ub3J0aF9kYXRhWyxhcmVhXzEwMDBzIDo9IGVhc3RfcGFjX25vcnRoX21vZCRjb2VmZmljaWVudHNbWzFdXS8xMDAwK2Vhc3RfcGFjX25vcnRoX21vZCRjb2VmZmljaWVudHNbWzJdXS8xMDAwKmxhdGl0dWRlX21pZF0KCmVhc3RfcGFjX3NvdXRoX2RhdGEgPC0gZGF0YS50YWJsZShsYXRpdHVkZV9taWQgPSB1bmlxdWUoZWFzdF9wYWNfc2hlbGZfYXJlYXNbbGF0aXR1ZGVfZW5kIDwwLF0kbGF0aXR1ZGVfbWlkKSkKCmVhc3RfcGFjX3NvdXRoX2RhdGFbLGFyZWFfMTAwMHMgOj0gZWFzdF9wYWNfc291dGhfbW9kJGNvZWZmaWNpZW50c1tbMV1dLzEwMDArZWFzdF9wYWNfc291dGhfbW9kJGNvZWZmaWNpZW50c1tbMl1dLzEwMDAqbGF0aXR1ZGVfbWlkXQoKYXJlYV9sYXRpdHVkZV9lYXN0X3BhYyAgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZWFzdF9wYWNfbm9ydGhfZGF0YSwgYWVzKHg9bGF0aXR1ZGVfbWlkLCB5ID0gYXJlYV8xMDAwcyksIGNvbG9yID0gImdyYXk2MCIsIHNpemUgPSAwLjgsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKwojICBnZW9tX2xpbmUoZGF0YSA9IGVhc3RfcGFjX3NvdXRoX2RhdGEsIGFlcyh4PWxhdGl0dWRlX21pZCwgeSA9IGFyZWFfMTAwMHMpLCBjb2xvciA9ICJncmF5NjAiLCBzaXplID0gMC44LCBsaW5ldHlwZSA9ICJsb25nZGFzaCIpICsgbm90IHNpZ25pZmljYW50CiAgZ2VvbV9wb2ludChkYXRhID0gZWFzdF9wYWNfc2hlbGZfYXJlYXMsIGFlcyh4PWxhdGl0dWRlX3N0YXJ0LCB5PWFyZWFfMTAwMHMpLCBzaGFwZSA9MTgsIHNpemUgPSAwLjcpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBlYXN0X3BhY19zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcyksIHNpemUgPSAwLjcpICsKICBnZW9tX3J1ZyhkYXRhID0gZWFzdF9wYWNfc2hlbGZfYXJlYXNfaGlnaGxpZ2h0LCBhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCBjb2xvciA9IGFzLmZhY3RvcihjaGFuZ2VfYWJvdmVfMmZvbGQpKSkgKwogbGFicyh4PXBhc3RlMCgiTGF0aXR1ZGUgIiwiXHUwMEIwIiwiRSIpLCB5ID0gZXhwcmVzc2lvbihwYXN0ZSgiQXJlYSAoMTAwMHMgb2YgIiwga21eezJ9LCIpIikpKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKG9wdGlvbiA9ICJBIiwgYmVnaW4gPSAwLjMsIGVuZCA9IDAuNywgbmFtZSA9ICJBc3NvY2lhdGVkIENoYW5nZVxuaW4gU2hlbGYgQXJlYSIsIGxhYmVscyA9IGMoIkNvbnRyYWN0aW9uIiwgIkV4cGFuc2lvbiIpKSArCiAgI2Fubm90YXRlKCJ0ZXh0IiwgeCA9IDgwLCB5ID0gMTMwMDAwLCBsYWJlbCA9ICJFYXN0ZXJuIFBhY2lmaWMgT2NlYW4iKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIHhsaW0obWluKGVhc3RfcGFjX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCksIG1heChlYXN0X3BhY19zaGVsZl9hcmVhcyRsYXRpdHVkZV9lbmQpKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDEwLCA0MCwgMTAsIDEwKSkKCiAgZ2dzYXZlKGFyZWFfbGF0aXR1ZGVfZWFzdF9wYWMsIGZpbGVuYW1lID0gImFyZWFfbGF0aXR1ZGVfZWFzdF9wYWNfMmRlZ3JlZXMuanBnIiwgaGVpZ2h0ID0gNCwgdW5pdHMgPSBjKCJpbiIpKQoKICAKd2VzdF9wYWNfbm9ydGhfZGF0YSA8LSBkYXRhLnRhYmxlKGxhdGl0dWRlX21pZCA9IHVuaXF1ZSh3ZXN0X3BhY19zaGVsZl9hcmVhc1tsYXRpdHVkZV9lbmQ+MCxdJGxhdGl0dWRlX21pZCkpCgp3ZXN0X3BhY19ub3J0aF9kYXRhWyxhcmVhXzEwMDBzIDo9IHdlc3RfcGFjX25vcnRoX21vZCRjb2VmZmljaWVudHNbWzFdXS8xMDAwK3dlc3RfcGFjX25vcnRoX21vZCRjb2VmZmljaWVudHNbWzJdXS8xMDAwKmxhdGl0dWRlX21pZF0KCndlc3RfcGFjX3NvdXRoX2RhdGEgPC0gZGF0YS50YWJsZShsYXRpdHVkZV9taWQgPSB1bmlxdWUod2VzdF9wYWNfc2hlbGZfYXJlYXNbbGF0aXR1ZGVfZW5kIDwwLF0kbGF0aXR1ZGVfbWlkKSkKCndlc3RfcGFjX3NvdXRoX2RhdGFbLGFyZWFfMTAwMHMgOj0gd2VzdF9wYWNfc291dGhfbW9kJGNvZWZmaWNpZW50c1tbMV1dLzEwMDArd2VzdF9wYWNfc291dGhfbW9kJGNvZWZmaWNpZW50c1tbMl1dLzEwMDAqbGF0aXR1ZGVfbWlkXQoKKGFyZWFfbGF0aXR1ZGVfd2VzdF9wYWMgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gd2VzdF9wYWNfbm9ydGhfZGF0YSwgYWVzKHg9bGF0aXR1ZGVfbWlkLCB5ID0gYXJlYV8xMDAwcyksIGNvbG9yID0gImdyYXk2MCIsIHNpemUgPSAwLjgsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9ICJncmF5NjAiLCBsYWJlbHMgPSAiQXJlYSB+IExhdGl0dWRlXG5MaW5lYXIgUmVncmVzc2lvbiIpICsKICBnZW9tX2xpbmUoZGF0YSA9IHdlc3RfcGFjX3NvdXRoX2RhdGEsIGFlcyh4PS1sYXRpdHVkZV9taWQsIHkgPSBhcmVhXzEwMDBzKSwgY29sb3IgPSAiZ3JheTYwIiwgc2l6ZSA9IDAuOCwgbGluZXR5cGUgPSAibG9uZ2Rhc2giKSArCiAgZ2VvbV9wb2ludChkYXRhID0gd2VzdF9wYWNfc2hlbGZfYXJlYXMsIGFlcyh4PWxhdGl0dWRlX3N0YXJ0LCB5PWFyZWFfMTAwMHMpLCBzaGFwZSA9MTgsIHNpemUgPSAwLjcpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSB3ZXN0X3BhY19zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcyksIHNpemUgPSAwLjcpICsKICBnZW9tX3J1ZyhkYXRhID0gd2VzdF9wYWNfc2hlbGZfYXJlYXNfaGlnaGxpZ2h0LCBhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCBjb2xvciA9IGFzLmZhY3RvcihjaGFuZ2VfYWJvdmVfMmZvbGQpKSkgKwogbGFicyh4PXBhc3RlMCgiTGF0aXR1ZGUgIiwiXHUwMEIwIiwiRSIpLCB5ID0gZXhwcmVzc2lvbihwYXN0ZSgiQXJlYSAoMTAwMHMgb2YgIiwga21eezJ9LCIpIikpKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKG9wdGlvbiA9ICJBIiwgYmVnaW4gPSAwLjMsIGVuZCA9IDAuNywgbmFtZSA9ICJBc3NvY2lhdGVkIENoYW5nZVxuaW4gU2hlbGYgQXJlYSIsIGxhYmVscyA9IGMoIkNvbnRyYWN0aW9uIiwgIkV4cGFuc2lvbiIpKSArCiAgI2Fubm90YXRlKCJ0ZXh0IiwgeCA9IDkwLCB5ID0gMTMwMDAwLCBsYWJlbCA9ICJXZXN0ZXJuIFBhY2lmaWMgT2NlYW4iKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIHhsaW0obWluKHdlc3RfcGFjX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCksIG1heCh3ZXN0X3BhY19zaGVsZl9hcmVhcyRsYXRpdHVkZV9lbmQpKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDEwLCA0MCwgMTAsIDEwKSkpCgogIAoKICBnZ3NhdmUoYXJlYV9sYXRpdHVkZV93ZXN0X3BhYywgZmlsZW5hbWUgPSAiYXJlYV9sYXRpdHVkZV93ZXN0X3BhY18yZGVncmVlcy5qcGciLCBoZWlnaHQgPSA0LCB1bml0cyA9IGMoImluIikpCiAgCiAgI3B1bGwgZ2VuZXJpYyBydWcgbGVnZW5kIG9ubHkKYXJlYV9sYXRpdHVkZV9ydWdfbGVnZW5kIDwtIGdldF9sZWdlbmQoYXJlYV9sYXRpdHVkZV93ZXN0X3BhYykKc2F2ZShhcmVhX2xhdGl0dWRlX3J1Z19sZWdlbmQsIGZpbGUgPSBoZXJlOjpoZXJlKCJGaWd1cmVzIiwgIkZpZ3VyZTNfNSIsICJhcmVhX2xhdGl0dWRlX3J1Z19sZWdlbmQuUkRhdGEiKSkKCmBgYApEdW1ieSBncmFwaCB0byBqdXN0IG1ha2UgYWRkaXRpb25hbCBsZWdlbmQgY29tcG9uZW50CmBgYHtyIGFkZGl0aW9uYWwgbGVnZW5kIGNvbXBvbmVudH0KbGVnZW5kX2xhdF9hcmVhX3JlZ3Jlc3Npb24gPC0gZ2V0X2xlZ2VuZCgKICBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSB3ZXN0X3BhY19ub3J0aF9kYXRhLCBhZXMoeD1sYXRpdHVkZV9taWQsIHkgPSBhcmVhXzEwMDBzLCBjb2xvciA9ICJ2YWx1ZSIpLCBzaXplID0gMC44LCBsaW5ldHlwZSA9ICJsb25nZGFzaCIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSAiZ3JheTYwIiwgbGFiZWxzID0gIkFyZWEgfiBMYXRpdHVkZVxuTGluZWFyIFJlZ3Jlc3Npb24iKSArCiAgICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDQwLCAxMCwgMTApLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKQoKc2F2ZShsZWdlbmRfbGF0X2FyZWFfcmVncmVzc2lvbiwgZmlsZSA9IGhlcmU6OmhlcmUoIkZpZ3VyZXMiLCAiRmlndXJlM181IiwgImxlZ2VuZF9sYXRfYXJlYV9yZWdyZXNzaW9uLlJEYXRhIikpCmBgYAoKSG93IG1hbnkgZXhwZXJpZW5jZSAnc2lnbmlmaWNhbnQnIGNoYW5nZXMgaW4gaGFiaXRhdCAoYXQgbGVhc3QgLTUwJSBvciArMTAwJSBjaGFuZ2UgZnJvbSBvbmUgYmluIHRvIGFub3RoZXIpIEkgd2lsbCBnbyB3aXRoIElVQ04gNTAlIGxvc3MgLT4gdnVsbmVyYWJsZSBzcGVjaWVzIGRlc2lnbmF0aW9uLgoKQmluIHNoaWZ0cyAtLT4gY29udHJhY3Rpb25zIChsb3NzIG9mIDUwJSkgdmVyc3VzIGV4cGFuc2lvbnMgKGdhaW4gb2YgMjAwJSkgdmVyc3VzIG5ldXRyYWwKYGBge3IgYmluIHNoaWZ0IGNhdGVnb3JpemF0aW9ufQoKbGlicmFyeShnZ3JlcGVsKQojY2FsbCBhbGwgb2JqZWN0cyBpbiBlbnZpcm9ubWVudCB3aXRoICJzdGF0cyIgc3RyaW5nCnN0YXRzX3N0cmluZzwtZ3JlcCgiYXJlYXNfc3RhdHMiLG5hbWVzKC5HbG9iYWxFbnYpLHZhbHVlPVRSVUUpCnN0YXRzX3N0cmluZ19saXN0PC1kby5jYWxsKCJsaXN0IixtZ2V0KHN0YXRzX3N0cmluZykpCm5hbWVzKHN0YXRzX3N0cmluZ19saXN0KSAjY2hlY2sKCiNyb3duYW1lcwpzdGF0c19zdHJpbmdfcm93bmFtZXMgPC0gcmVwKG5hbWVzKHN0YXRzX3N0cmluZ19saXN0KSwgZWFjaCA9IDMpCnN0YXRzX3N0cmluZ190eXBlIDwtIHJlcChjKCJjb250cmFjdGlvbiIsICJuZXV0cmFsIiwgImV4cGFuc2lvbiIpLHRpbWVzID0gNikKCiNjaGVjayA8LSBjKCJFYXN0ZXJuIEluZGlhbiBPY2VhbiIgLCJXZXN0ZXJuIFBhY2lmaWMgT2NlYW4iICwiRWFzdGVybiBQYWNpZmljIE9jZWFuIiAsIldlc3Rlcm4gQXRsYW50aWMgT2NlYW4iICwiV2VzdGVybiBJbmRpYW4gT2NlYW4iICwiRWFzdGVybiBBdGxhbnRpYyBPY2VhbiIpCgpzaWduaWZpY2FudF9jaGFuZ2VzIDwtIGFzLmRhdGEudGFibGUocmJpbmQoc3RhdHNfc3RyaW5nX2xpc3RbWzFdXSxzdGF0c19zdHJpbmdfbGlzdFtbMl1dLHN0YXRzX3N0cmluZ19saXN0W1szXV0sc3RhdHNfc3RyaW5nX2xpc3RbWzRdXSxzdGF0c19zdHJpbmdfbGlzdFtbNV1dLHN0YXRzX3N0cmluZ19saXN0W1s2XV0pKQoKc2lnbmlmaWNhbnRfY2hhbmdlc1ssIHJlZ2lvbiA6PSBzdGF0c19zdHJpbmdfcm93bmFtZXNdWyx0eXBlIDo9IHN0YXRzX3N0cmluZ190eXBlXQoKI21lbHQgdG8gcGxvdApzaWduaWZpY2FudF9jaGFuZ2VzLmxvbmcgPC0gbWVsdChzaWduaWZpY2FudF9jaGFuZ2VzLCBpZC52YXJzID0gYygicmVnaW9uIiwidHlwZSIpLCB2YXJpYWJsZS5uYW1lID0gImhlbWlzcGhlcmUiLCBtZWFzdXJlLnZhcnMgPSBjKCJub3J0aCIsICJzb3V0aCIpKQoKI2NhbGN1bGF0ZSBwZXJjZW50YWdlcwpzaWduaWZpY2FudF9jaGFuZ2VzLmxvbmdbLHRvdGFsX2JpbnNfaGVtaXNwaGVyZSA6PSBzdW0odmFsdWUpLC4ocmVnaW9uLCBoZW1pc3BoZXJlKV1bLHRvdGFsX2JpbnNfcmVnaW9uIDo9IHN1bSh2YWx1ZSkscmVnaW9uXVsscGVyY2VudF9ieV9oZW1pc3BoZXJlIDo9IHJvdW5kKHN1bSh2YWx1ZSkvdG90YWxfYmluc19oZW1pc3BoZXJlKjEwMCwyKSwuKHJlZ2lvbixoZW1pc3BoZXJlLHR5cGUpXVsscGVyY2VudF9ieV9yZWdpb24gOj0gcm91bmQoc3VtKHZhbHVlKS90b3RhbF9iaW5zX3JlZ2lvbioxMDAsMiksIC4ocmVnaW9uLHR5cGUpXQoKc2lnbmlmaWNhbnRfY2hhbmdlcy5sb25nWyx0eXBlIDo9IGZhY3Rvcih0eXBlLCBsZXZlbHMgPSBjKCJjb250cmFjdGlvbiIsIm5ldXRyYWwiLCJleHBhbnNpb24iKSldWyxyZWdpb25fbmFtZXMgOj0gZmFjdG9yKHJlZ2lvbiwgbGV2ZWxzID0gYygiZWFzdF9hdGxfc2hlbGZfYXJlYXNfc3RhdHMiLCAid2VzdF9hdGxfc2hlbGZfYXJlYXNfc3RhdHMiLCAiZWFzdF9pbmRfc2hlbGZfYXJlYXNfc3RhdHMiLCAid2VzdF9pbmRfc2hlbGZfYXJlYXNfc3RhdHMiICwiZWFzdF9wYWNfc2hlbGZfYXJlYXNfc3RhdHMiICwid2VzdF9wYWNfc2hlbGZfYXJlYXNfc3RhdHMiKSwgbGFiZWxzID0gYygiRWFzdCBBdGxhbnRpYyIsICJXZXN0IEF0bGFudGljIiwgIkVhc3QgSW5kaWFuIiwgIldlc3QgSW5kaWFuIiAsIkVhc3QgUGFjaWZpYyIgLCJXZXN0IFBhY2lmaWMiKSldWyxoZW1pc3BoZXJlIDo9IGZhY3RvcihoZW1pc3BoZXJlLGxldmVscyA9IGMoIm5vcnRoIiwic291dGgiKSwgbGFiZWxzID0gYygiTm9ydGgiLCJTb3V0aCIpKV0KCgoKCmJsYW5rX3RoZW1lIDwtIHRoZW1lX21pbmltYWwoKSsKICB0aGVtZSgKICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5ncmlkPWVsZW1lbnRfYmxhbmsoKSwKICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQsIGZhY2U9ImJvbGQiKQogICkKCiN2aXJpZGlzIG1hZ21hIHBhbGV0dGUsIENvbnRyYWN0aW9ucyBbMV0sIGV4cGFuc2lvbnNbMl0pCnZpcmlkaXNfZXhwX2NvbnQgPC12aXJpZGlzX3BhbChiZWdpbiA9IDAuMywgZW5kID0gMC43LCBvcHRpb24gPSAiQSIpKDIpCgojYnkgaGVtaXNwaGVyZQoKZ2dwbG90KGRhdGEgPSBzaWduaWZpY2FudF9jaGFuZ2VzLmxvbmcsIGFlcyh4PSIiLCB5ID0gcGVyY2VudF9ieV9oZW1pc3BoZXJlLCBmaWxsID0gdHlwZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxLCBhbHBoYSA9IDAuOCkgKwogIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQ9MCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGModmlyaWRpc19leHBfY29udFsxXSwgImdyZXk5NCIsIHZpcmlkaXNfZXhwX2NvbnRbMl0pLCBuYW1lID0gIlNoZWxmIEFyZWEgQ2hhbmdlIiwgbGFiZWxzID0gYygiQ29udHJhY3Rpb24iLCAiTmVpdGhlciIsICJFeHBhbnNpb24iKSkgKwogIGZhY2V0X2dyaWQoaGVtaXNwaGVyZX5yZWdpb25fbmFtZXMpICsKICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKHBlcmNlbnRfYnlfaGVtaXNwaGVyZSwxKSwiJSIpKSwgc2l6ZSA9IDEsIGZvbnRmYWNlID0gImJvbGQiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC4zKSkgKwogIHNjYWxlX3hfZGlzY3JldGUoZXhwYW5kID0gYygwLDApKSArCiAgYmxhbmtfdGhlbWUgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLCAKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNykpICsKICBndWlkZXMoc2hhcGUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMC41KSksIAogICAgICAgICBmaWxsID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDAuNSkpKQoKZ2dzYXZlKGZpbGVuYW1lID0gImZpZ3VyZTZfaGFiaXRhdGxvc3NfZ2Fpbl8yZm9sZF9ieWhlbWlzcGhlcmUuanBnIiwgaGVpZ2h0ID0gMiwgd2lkdGggPSA2LCB1bml0ID0gImluIikKZ2dzYXZlKGZpbGVuYW1lID0gImZpZ3VyZTZfaGFiaXRhdGxvc3NfZ2Fpbl8yZm9sZF9ieWhlbWlzcGhlcmUuZXBzIiwgaGVpZ2h0ID0gMiwgd2lkdGggPSA2LCB1bml0ID0gImluIikKCgojYnkgcmVnaW9uIChoZW1pc3BoZXJlJ3MgY29tcHJlc3NlZCkKZ2dwbG90KGRhdGEgPSB1bmlxdWUoc2lnbmlmaWNhbnRfY2hhbmdlcy5sb25nWywuKHJlZ2lvbl9uYW1lcyx0eXBlLHBlcmNlbnRfYnlfcmVnaW9uKV0pLCBhZXMoeD0iIiwgeSA9IHBlcmNlbnRfYnlfcmVnaW9uLCBmaWxsID0gdHlwZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxKSArCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydD0wKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyh2aXJpZGlzX2V4cF9jb250WzFdLCAiZ3JleTk0IiwgdmlyaWRpc19leHBfY29udFsyXSksIG5hbWUgPSAiU2hlbGYgQXJlYSBDaGFuZ2UiLCBsYWJlbHMgPSBjKCJDb250cmFjdGlvbiIsICJOZWl0aGVyIiwgIkV4cGFuc2lvbiIpKSArCiAgZmFjZXRfd3JhcCh+cmVnaW9uX25hbWVzKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChwZXJjZW50X2J5X3JlZ2lvbiwiJSIpKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuMSksIHNpemUgPSAyKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBjKDAsMCkpICsKICBibGFua190aGVtZSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKQoKZ2dzYXZlKGZpbGVuYW1lID0gImZpZ3VyZTZfaGFiaXRhdGxvc3NfZ2Fpbl8yZm9sZF9ieXJlZ2lvbi5qcGciLCBoZWlnaHQgPSA0LCB3aWR0aCA9IDgsIHVuaXQgPSAiaW4iKQpnZ3NhdmUoZmlsZW5hbWUgPSAiZmlndXJlNl9oYWJpdGF0bG9zc19nYWluXzJmb2xkX2J5cmVnaW9uLmVwcyIsIGhlaWdodCA9IDQsIHdpZHRoID0gOCwgdW5pdCA9ICJpbiIpCgoKYGBgCgpOb3csIEkgc2hvdWxkIG1ha2UgbWFwcyBmb3IgZWFjaCBvZiB0aGVzZSByZWdpb25zCgpVc2VkIGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL3ZhbGVudGluaXRuZWxhdi9jNzU5OGZjZmM4ZTUzNjU4ZjY2ZmVlYTlkM2JhZmI0MCBmb3IgaW5zdHJ1Y3Rpb25zCgpgYGB7ciBzZXR1cCB3b3JsZCBtYXBzfQpsaWJyYXJ5KGdnc3BhdGlhbCkKCiAgd29ybGQgPC0gbmVfY291bnRyaWVzKHNjYWxlID0gIm1lZGl1bSIsIHJldHVybmNsYXNzID0gInNmIikKCiMgfn5+fn5+fn5+fn4gRG93bmxvYWQgc2hhcGVmaWxlIGZyb20gd3d3Lm5hdHVyYWxlYXJ0aGRhdGEuY29tIH5+fn5+fn5+fn5+ICMKIyBEb3dubG9hZCBjb3VudHJpZXMgZGF0YQojZG93bmxvYWQuZmlsZSh1cmwgPSAiaHR0cDovL3d3dy5uYXR1cmFsZWFydGhkYXRhLmNvbS9odHRwLy93d3cubmF0dXJhbGVhcnRoZGF0YS5jb20vZG93bmxvYWQvMTEwbS9jdWx0dXJhbC9uZV8xMTBtX2FkbWluXzBfY291bnRyaWVzLnppcCIsIAojICAgICAgICAgICAgICBkZXN0ZmlsZSA9ICJuZV8xMTBtX2FkbWluXzBfY291bnRyaWVzLnppcCIpCiMgdW56aXAgdGhlIHNoYXBlZmlsZSBpbiB0aGUgZGlyZWN0b3J5IG1lbnRpb25lZCB3aXRoICJleGRpciIgYXJndW1lbnQKI3VuemlwKHppcGZpbGU9Im5lXzExMG1fYWRtaW5fMF9jb3VudHJpZXMuemlwIiwgZXhkaXIgPSAibmVfMTEwbV9hZG1pbl8wX2NvdW50cmllcyIpCiMgZGVsZXRlIHRoZSB6aXAgZmlsZQojZmlsZS5yZW1vdmUoIm5lXzExMG1fYWRtaW5fMF9jb3VudHJpZXMuemlwIikKIyByZWFkIHRoZSBzaGFwZWZpbGUgd2l0aCByZWFkT0dSIGZyb20gcmdkYWwgcGFja2FnZQpORV9jb3VudHJpZXMgPC0gcmVhZE9HUihkc24gPSAibmVfMTEwbV9hZG1pbl8wX2NvdW50cmllcyIsIGxheWVyID0gIm5lXzExMG1fYWRtaW5fMF9jb3VudHJpZXMiKQpjbGFzcyhORV9jb3VudHJpZXMpICMgaXMgYSBTcGF0aWFsUG9seWdvbnNEYXRhRnJhbWUgb2JqZWN0CgojIH5+fn5+fn5+fn5+IFNwbGl0IHdvcmxkIG1hcCBieSAic3BsaXQgbGluZSIgfn5+fn5+fn5+fn4gIwoKIyBzaGlmdCBjZW50cmFsL3ByaW1lIG1lcmlkaWFuIHRvd2FyZHMgd2VzdCDigJMgcG9zaXRpdmUgdmFsdWVzIG9ubHkKc2hpZnQgPC0gMTgwICszMAoKIyBjcmVhdGUgInNwbGl0IGxpbmUiIHRvIHNwbGl0IGNvdW50cnkgcG9seWdvbnMKV0dTODQgPC0gQ1JTKCIrcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCArbm9fZGVmcyArZWxscHM9V0dTODQgK3Rvd2dzODQ9MCwwLDAiKQpzcGxpdC5saW5lIDwtIFNwYXRpYWxMaW5lcyhsaXN0KExpbmVzKGxpc3QoTGluZShjYmluZCgxODAtc2hpZnQsYygtOTAsOTApKSkpLCBJRD0ibGluZSIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvajRzdHJpbmc9V0dTODQpCgojIE5PVEUgLSBpbiBjYXNlIG9mIFRvcG9sb2d5RXhjZXB0aW9uJyBlcnJvcnMgd2hlbiBpbnRlcnNlY3RpbmcgbGluZSB3aXRoIGNvdW50cnkgcG9seWdvbnMsCiMgYXBwbHkgdGhlIGdCdWZmZXIgc29sdXRpb24gc3VnZ2VzdGVkIGF0OgojIGh0dHA6Ly9naXMuc3RhY2tleGNoYW5nZS5jb20vcXVlc3Rpb25zLzE2MzQ0NS9yLXNvbHV0aW9uLWZvci10b3BvbG9neWV4Y2VwdGlvbi1pbnB1dC1nZW9tLTEtaXMtaW52YWxpZC1zZWxmLWludGVyc2VjdGlvbi1lcgpORV9jb3VudHJpZXMgPC0gZ0J1ZmZlcihORV9jb3VudHJpZXMsIGJ5aWQ9VFJVRSwgd2lkdGg9MCkKCiMgaW50ZXJzZWN0aW5nIGxpbmUgd2l0aCBjb3VudHJ5IHBvbHlnb25zCmxpbmUuZ0ludCA8LSBnSW50ZXJzZWN0aW9uKHNwbGl0LmxpbmUsIE5FX2NvdW50cmllcykKCiMgY3JlYXRlIGEgdmVyeSB0aGluIHBvbHlnb24gKGJ1ZmZlcikgb3V0IG9mIHRoZSBpbnRlcnNlY3RpbmcgInNwbGl0IGxpbmUiCmJmIDwtIGdCdWZmZXIobGluZS5nSW50LCBieWlkPVRSVUUsIHdpZHRoPTAuMDAwMDAxKSAgCgojIHNwbGl0IGNvdW50cnkgcG9seWdvbnMgdXNpbmcgaW50ZXJzZWN0aW5nIHRoaW4gcG9seWdvbiAoYnVmZmVyKQpORV9jb3VudHJpZXMuc3BsaXQgPC0gZ0RpZmZlcmVuY2UoTkVfY291bnRyaWVzLCBiZiwgYnlpZD1UUlVFKQojIHBsb3QoTkVfY291bnRyaWVzLnNwbGl0KSAjIGNoZWNrIG1hcApjbGFzcyhORV9jb3VudHJpZXMuc3BsaXQpICMgaXMgYSBTcGF0aWFsUG9seWdvbnMgb2JqZWN0CgojIH5+fn5+fn5+fn5+IENyZWF0ZSBncmF0aWN1bGVzIH5+fn5+fn5+fn5+ICMKIyBjcmVhdGUgYSBib3VuZGluZyBib3ggLSB3b3JsZCBleHRlbnQKYi5ib3ggPC0gYXMocmFzdGVyOjpleHRlbnQoLTE4MCwgMTgwLCAtOTAsIDkwKSwgIlNwYXRpYWxQb2x5Z29ucyIpCiMgYXNzaWduIENSUyB0byBib3gKcHJvajRzdHJpbmcoYi5ib3gpIDwtIFdHUzg0CiMgY3JlYXRlIGdyYXRpY3VsZXMvZ3JpZCBsaW5lcyBmcm9tIGJveApncmlkIDwtIGdyaWRsaW5lcyhiLmJveCwgCiAgICAgICAgICAgICAgICAgIGVhc3RzICA9IHNlcShmcm9tPS0xODAsIHRvPTE4MCwgYnk9MjApLAogICAgICAgICAgICAgICAgICBub3J0aHMgPSBzZXEoZnJvbT0tOTAsIHRvPTkwLCBieT0xMCkpCgojIGNyZWF0ZSBsYWJlbHMgZm9yIGdyYXRpY3VsZXMKZ3JpZC5sYmwgPC0gbGFiZWxzKGdyaWQsIHNpZGUgPSAxOjQpCgojIHRyYW5zZm9ybSBsYWJlbHMgZnJvbSBTcGF0aWFsUG9pbnRzRGF0YUZyYW1lIHRvIGEgZGF0YSB0YWJsZSB0aGF0IGdncGxvdCBjYW4gdXNlCmdyaWQubGJsLkRUIDwtIGRhdGEudGFibGUoZ3JpZC5sYmxAY29vcmRzLCBncmlkLmxibEBkYXRhKQoKIyBwcmVwYXJlIGxhYmVscyB3aXRoIHJlZ3VsYXIgZXhwcmVzc2lvbjoKIyAtIGRlbGV0ZSB1bndhbnRlZCBsYWJlbHMKZ3JpZC5sYmwuRFRbLCBsYWJlbHMgOj0gZ3N1YihwYXR0ZXJuPSIxODBcXCpkZWdyZWV8OTBcXCpkZWdyZWVcXCpOfDkwXFwqZGVncmVlXFwqUyIsIHJlcGxhY2VtZW50PSIiLCB4PWxhYmVscyldCiMgLSByZXBsYWNlIHBhdHRlcm4gIipkZWdyZWUiIHdpdGggIsKwIiAoKiBuZWVkcyB0byBiZSBlc2NhcGVkIHdpdGggXFwpCmdyaWQubGJsLkRUWywgbGJsIDo9IGdzdWIocGF0dGVybj0iXFwqZGVncmVlIiwgcmVwbGFjZW1lbnQ9IsKwIiwgeD1sYWJlbHMpXQojIC0gZGVsZXRlIGFueSByZW1haW5pbmcgIioiCmdyaWQubGJsLkRUWywgbGJsIDo9IGdzdWIocGF0dGVybj0iKlxcKiIsIHJlcGxhY2VtZW50PSIiLCB4PWxibCldCgojIGFkanVzdCBjb29yZGluYXRlcyBvZiBsYWJlbHMgc28gdGhhdCB0aGV5IGZpdCBpbnNpZGUgdGhlIGdsb2JlCmdyaWQubGJsLkRUWywgbG9uZyA6PSBpZmVsc2UoY29vcmRzLngxICVpbiUgYygtMTgwLDE4MCksIGNvb3Jkcy54MSoxNzUvMTgwLCBjb29yZHMueDEpXQpncmlkLmxibC5EVFssIGxhdCAgOj0gaWZlbHNlKGNvb3Jkcy54MiAlaW4lIGMoLTkwLDkwKSwgY29vcmRzLngyKjgyLzkwLCBjb29yZHMueDIpXQoKIyB+fn5+fn5+fn5+fiBQcmVwYXJlIGRhdGEgZm9yIGdncGxvdCwgc2hpZnQgJiBwcm9qZWN0IGNvb3JkaW5hdGVzIH5+fn5+fn5+fn5+ICMKIyBnaXZlIHRoZSBQT1JKLjQgc3RyaW5nIGZvciBFY2tlcnQgSVYgcHJvamVjdGlvbiAoIGNoYW5nZWQgdG8gZGlmZmVyZW50IHByb2plY3Rpb24sICIrcHJvaj1lY2s0ICtsb25fMD0wICt4XzA9MCAreV8wPTAgK2VsbHBzPVdHUzg0ICtkYXR1bT1XR1M4NCArdW5pdHM9bSArbm9fZGVmcyIgZm9yIGVja2VydCkKUFJPSiA8LSAiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQgK25vX2RlZnMgK2VsbHBzPVdHUzg0ICt0b3dnczg0PTAsMCwwIiAKCiMgdHJhbnNmb3JtIGdyYXRpY3VsZXMgZnJvbSBTcGF0aWFsTGluZXMgdG8gYSBkYXRhIHRhYmxlIHRoYXQgZ2dwbG90IGNhbiB1c2UKZ3JpZC5EVCA8LSBkYXRhLnRhYmxlKG1hcF9kYXRhKFNwYXRpYWxMaW5lc0RhdGFGcmFtZShzbD1ncmlkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRhdGEuZnJhbWUoMTpsZW5ndGgoZ3JpZCkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaC5JRCA9IEZBTFNFKSkpCiMgcHJvamVjdCBjb29yZGluYXRlcwojIGFzc2lnbiBtYXRyaXggb2YgcHJvamVjdGVkIGNvb3JkaW5hdGVzIGFzIHR3byBjb2x1bW5zIGluIGRhdGEgdGFibGUKZ3JpZC5EVFssIGMoIlgiLCJZIikgOj0gZGF0YS50YWJsZShwcm9qZWN0KGNiaW5kKGxvbmcsIGxhdCksIHByb2o9UFJPSikpXQoKIyBwcm9qZWN0IGNvb3JkaW5hdGVzIG9mIGxhYmVscwpncmlkLmxibC5EVFssIGMoIlgiLCJZIikgOj0gZGF0YS50YWJsZShwcm9qZWN0KGNiaW5kKGxvbmcsIGxhdCksIHByb2o9UFJPSikpXQoKIyB0cmFuc2Zvcm0gc3BsaXQgY291bnRyeSBwb2x5Z29ucyBpbiBhIGRhdGEgdGFibGUgdGhhdCBnZ3Bsb3QgY2FuIHVzZQpDb3VudHJ5LkRUX3NoaWZ0IDwtIGRhdGEudGFibGUobWFwX2RhdGEoYXMoTkVfY291bnRyaWVzLnNwbGl0LCAiU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lIikpKQpDb3VudHJ5LkRUIDwtIGRhdGEudGFibGUobWFwX2RhdGEoYXMoTkVfY291bnRyaWVzLCAiU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lIikpKQojIFNoaWZ0IGNvb3JkaW5hdGVzCkNvdW50cnkuRFRfc2hpZnRbLCBsb25nLm5ldyA6PSBsb25nICsgc2hpZnRdCkNvdW50cnkuRFRfc2hpZnRbLCBsb25nLm5ldyA6PSBpZmVsc2UobG9uZy5uZXcgPiAxODAsIGxvbmcubmV3LTM2MCwgbG9uZy5uZXcpXQoKIyBwcm9qZWN0IGNvb3JkaW5hdGVzIApDb3VudHJ5LkRUWywgYygiWCIsIlkiKSA6PSBkYXRhLnRhYmxlKHByb2plY3QoY2JpbmQobG9uZywgbGF0KSwgcHJvaj1QUk9KKSldCkNvdW50cnkuRFRfc2hpZnRbLCBjKCJYIiwiWSIpIDo9IGRhdGEudGFibGUocHJvamVjdChjYmluZChsb25nLm5ldywgbGF0KSwgcHJvaj1QUk9KKSldCgojIH5+fn5+fn5+fn5+IFBsb3QgbWFwIH5+fn5+fn5+fn5+ICMKZ2dwbG90KCkgKyAKICAgICMgYWRkIHByb2plY3RlZCBjb3VudHJpZXMKICAgIGdlb21fcG9seWdvbihkYXRhID0gQ291bnRyeS5EVF9zaGlmdCwgCiAgICAgICAgICAgICAgICAgYWVzKHggPSBsb25nLm5ldysxNTAsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXApLCAKICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JheTcwIiwgCiAgICAgICAgICAgICAgICAgZmlsbCA9ICJncmF5OTAiLCAKICAgICAgICAgICAgICAgICBzaXplID0gMC4yNSkgKwogICAgIyBhZGQgZ3JhdGljdWxlcwogICAgZ2VvbV9wYXRoKGRhdGEgPSBncmlkLkRULCAKICAgICAgICAgICAgICBhZXMoeCA9IFgsIHkgPSBZLCBncm91cCA9IGdyb3VwKSwgCiAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZG90dGVkIiwgY29sb3VyID0gImdyZXk1MCIsIHNpemUgPSAuMjUpICsKICAgICMgYWRkIGEgYm91bmRpbmcgYm94IChzZWxlY3QgZ3JhdGljdWxlcyBhdCBlZGdlcykKICAgIGdlb21fcGF0aChkYXRhID0gZ3JpZC5EVFsobG9uZyAlaW4lIGMoLTE4MCwxODApICYgcmVnaW9uID09ICJOUyIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfChsb25nICVpbiUgYygtMTgwLDE4MCkgJiBsYXQgJWluJSBjKC05MCw5MCkgJiByZWdpb24gPT0gIkVXIildLCAKICAgICAgICAgICAgICBhZXMoeCA9IFgsIHkgPSBZLCBncm91cCA9IGdyb3VwKSwgCiAgICAgICAgICAgICAgbGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gLjMpICsKICAgICMgYWRkIGdyYXRpY3VsZSBsYWJlbHMKICAgIGdlb21fdGV4dChkYXRhID0gZ3JpZC5sYmwuRFQsICMgbGF0aXR1ZGUKICAgICAgICAgICAgICBhZXMoeCA9IFgsIHkgPSBZLCBsYWJlbCA9IGxibCksIAogICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5NTAiLCBzaXplID0gMikgKwogICAgIyBlbnN1cmVzIHRoYXQgb25lIHVuaXQgb24gdGhlIHgtYXhpcyBpcyB0aGUgc2FtZSBsZW5ndGggYXMgb25lIHVuaXQgb24gdGhlIHktYXhpcwogICAgY29vcmRfZXF1YWwoKSArICMgc2FtZSBhcyBjb29yZF9maXhlZChyYXRpbyA9IDEpCiAgICAjIHNldCBlbXB0eSB0aGVtZQogICAgdGhlbWVfdm9pZCgpCgpgYGAKCmBgYHtyIG1hcHBpbmcgZWFjaCByZWdpb259CgpyZWdpb25fbWFwcyA8LSBsaXN0KCkKcmVnaW9uc19zaGlmdF9wcm9qZWN0aW9uIDwtIGMoIndlc3RfcGFjX3NwZGZfc2hpZnQiLCAiZWFzdF9wYWNfc3BkZl9zaGlmdCIpCgoKI2NoYW5nZSBuYW1lcyB0byBtYXRjaCBuZXcgbWVyZ2VkIHJlZ2lvbnMgd2l0aCBub24tTE1FcyAobWFza19mdWxsKQplYXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfZnVsbCA8LSBlYXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMKd2VzdF9hdGxfc3BkZl9tYXNrX2Z1bGwgPC0gd2VzdF9hdGxfc3BkZl9tYXNrXzFzCndlc3RfaW5kX3NwZGZfbWFza19mdWxsIDwtIHdlc3RfaW5kX3NwZGZfbWFza18xcwplYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfZnVsbCA8LSBlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMKd2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrX2Z1bGwgPC0gd2VzdF9wYWNfc3BkZl9tYXNrX2Z1bGwKZWFzdF9pbmRfc3BkZl9tYXNrX2Z1bGwgPC0gZWFzdF9pbmRfc3BkZl9tYXNrXzFzCgoKCgpmb3IgKGkgaW4gMTpsZW5ndGgocmVnaW9uX25hbWVzKSkgewogIAogIHJlZ2lvbl9zcGRmIDwtIGdldChwYXN0ZTAocmVnaW9uX25hbWVzW2ldLCAiX21hc2siKSkKICAKICBpZihyZWdpb25fbmFtZXNbaV0gJWluJSByZWdpb25zX3NoaWZ0X3Byb2plY3Rpb24pIHsKICAKICAjcGFjaWZpYyBjZW50ZXJlZCBwcm9qZWN0aW9uCiAgCiAgcmVnaW9uX3NwZGZfbWFza18xc19leHRlbnQgPC0gZXh0ZW50KGdldChwYXN0ZTAocmVnaW9uX25hbWVzW2ldLCJfbWFza19mdWxsIikpKSAjIHRha2UgZXh0ZW50IG9mIHJlZ2lvbgogIAogICNjb252ZXJ0IHJhc3RlcnMgdG8gZGZzIGRhdGEgZnJhbWUKICByZWdpb25fc3BkZiA8LSBhcyhnZXQocGFzdGUwKHJlZ2lvbl9uYW1lc1tpXSwiX21hc2tfZnVsbCIpKSwgIlNwYXRpYWxQaXhlbHNEYXRhRnJhbWUiKQogIHJlZ2lvbl9kZiA8LSBhcy5kYXRhLmZyYW1lKHJlZ2lvbl9zcGRmKQogIGNvbG5hbWVzKHJlZ2lvbl9kZikgPC0gYygidmFsdWUiLCAieCIsICJ5IikKICAKICAKICAocmVnaW9uX21hcHNbW2ldXSA8LSBnZ3Bsb3QoKSArIAogICAgIyBhZGQgcHJvamVjdGVkIGNvdW50cmllcwogICAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBDb3VudHJ5LkRUX3NoaWZ0LCAKICAgICAgICAgICAgICAgICBhZXMoeCA9IGxvbmcubmV3KzE1MCwgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCksIAogICAgICAgICAgICAgICAgIGNvbG91ciA9ICJncmF5NzAiLCAKICAgICAgICAgICAgICAgICBmaWxsID0gImdyYXk5MCIsIAogICAgICAgICAgICAgICAgIHNpemUgPSAwLjI1KSArCiAgICBnZW9tX3RpbGUoZGF0YSA9IHJlZ2lvbl9kZiwgYWVzKHggPSB4LCB5ID0geSwgZmlsbCA9IHZhbHVlLCBjb2xvciA9ICJsaWdodHN0ZWVsYmx1ZTQiKSwgY29sb3IgPSAibGlnaHRzdGVlbGJsdWU0IikgKwogICAgY29vcmRfc2YoeCA9IGMocmVnaW9uX3NwZGZfbWFza18xc19leHRlbnRbMV0sIHJlZ2lvbl9zcGRmX21hc2tfMXNfZXh0ZW50WzJdKSwgeSA9IGMocmVnaW9uX3NwZGZfbWFza18xc19leHRlbnRbM10sIHJlZ2lvbl9zcGRmX21hc2tfMXNfZXh0ZW50WzRdKSkgKwogICAgbGFicyggeCA9IHBhc3RlMCgiTG9uZ2l0dWRlICIsICJcdTAwQjBFIiksIHkgPSBwYXN0ZTAoIkxhdGl0dWRlICIsICJcdTAwQjBFIikpICsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMCkgKwogICAgdGhlbWVfY2xhc3NpYygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCiAgCiAgZmlsZW5hbWUgPC0gcGFzdGUwKHJlZ2lvbl9uYW1lc1tpXSwgIl9tYXBfMmRlZ3JlZXMuanBnIikKICBnZ3NhdmUocGxvdCA9IHJlZ2lvbl9tYXBzW1tpXV0sIGZpbGVuYW1lID0gZmlsZW5hbWUsIGhlaWdodCA9IDQsIHVuaXRzID0gYygiaW4iKSkKICAKICB9IGVsc2UgewoKICAjYXRsYW50aWMgY2VudGVyZWQgcHJvamVjdGlvbgogIHJlZ2lvbl9zcGRmX21hc2tfMXNfZXh0ZW50IDwtIGV4dGVudChnZXQocGFzdGUwKHJlZ2lvbl9uYW1lc1tpXSwiX21hc2tfZnVsbCIpKSkgIyB0YWtlIGV4dGVudCBvZiByZWdpb24KICAKICAjY29udmVydCByYXN0ZXJzIHRvIGRmcyBkYXRhIGZyYW1lCiAgcmVnaW9uX3NwZGYgPC0gYXMoZ2V0KHBhc3RlMChyZWdpb25fbmFtZXNbaV0sIl9tYXNrX2Z1bGwiKSksICJTcGF0aWFsUGl4ZWxzRGF0YUZyYW1lIikKICByZWdpb25fZGYgPC0gYXMuZGF0YS5mcmFtZShyZWdpb25fc3BkZikKICBjb2xuYW1lcyhyZWdpb25fZGYpIDwtIGMoInZhbHVlIiwgIngiLCAieSIpCiAgCiAgCiAgKHJlZ2lvbl9tYXBzW1tpXV0gPC0gZ2dwbG90KCkgKyAKICAgICMgYWRkIHByb2plY3RlZCBjb3VudHJpZXMKICAgIGdlb21fcG9seWdvbihkYXRhID0gQ291bnRyeS5EVCwgCiAgICAgICAgICAgICAgICAgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwgCiAgICAgICAgICAgICAgICAgY29sb3VyID0gImdyYXk3MCIsIAogICAgICAgICAgICAgICAgIGZpbGwgPSAiZ3JheTkwIiwgCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMjUpICsKICAgIGdlb21fdGlsZShkYXRhID0gcmVnaW9uX2RmLCBhZXMoeCA9IHgsIHkgPSB5LCBmaWxsID0gYXMuZmFjdG9yKHZhbHVlKSkpICsKICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gImxpZ2h0c3RlZWxibHVlNCIsIGxhYmVscyA9ICJDb250aW5lbnRhbCBTaGVsZiBBcmVhIikgKwogICAgY29vcmRfc2YoeCA9IGMocmVnaW9uX3NwZGZfbWFza18xc19leHRlbnRbMV0sIHJlZ2lvbl9zcGRmX21hc2tfMXNfZXh0ZW50WzJdKSwgeSA9IGMocmVnaW9uX3NwZGZfbWFza18xc19leHRlbnRbM10sIHJlZ2lvbl9zcGRmX21hc2tfMXNfZXh0ZW50WzRdKSkgKwogICAgbGFicyggeCA9IHBhc3RlMCgiTG9uZ2l0dWRlICIsICJcdTAwQjBFIiksIHkgPSBwYXN0ZTAoIkxhdGl0dWRlICIsICJcdTAwQjBOIikpICsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMCkgKwogICAgdGhlbWVfY2xhc3NpYygpICsKICAgICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSkKICAKICBmaWxlbmFtZSA8LSBwYXN0ZTAocmVnaW9uX25hbWVzW2ldLCAiX21hcF8yZGVncmVlcy5qcGciKQogIGdnc2F2ZShwbG90ID0gcmVnaW9uX21hcHNbW2ldXSwgZmlsZW5hbWUgPSBmaWxlbmFtZSwgaGVpZ2h0ID0gNCwgdW5pdHMgPSBjKCJpbiIpKQogIAogIH0KICAKfQoKcmVnaW9uX21hcF9sZWdlbmQgPC0gZ2V0X2xlZ2VuZChyZWdpb25fbWFwc1tbNl1dKQoKI3NhdmUgbWFwcwpzYXZlKHJlZ2lvbl9tYXBzLCBmaWxlID0gaGVyZTo6aGVyZSgiRmlndXJlcyIsIkZpZ3VyZTNfNSIsICJyZWdpb25fbWFwcy5SRGF0YSIpKQojc2F2ZSBtYXAgbGVnZW5kCnNhdmUocmVnaW9uX21hcF9sZWdlbmQsIGZpbGUgPSBoZXJlOjpoZXJlKCJGaWd1cmVzIiwiRmlndXJlM181IiwgInJlZ2lvbl9tYXBzX2xlZ2VuZC5SRGF0YSIpKQoKI3NhdmUgYWxsIGFyZWEgdmVyc3VzIGxhdGl0dWRlIHBsb3RzIApzYXZlKGFyZWFfbGF0aXR1ZGVfZWFzdF9wYWMgLCBhcmVhX2xhdGl0dWRlX3dlc3RfcGFjICwgYXJlYV9sYXRpdHVkZV9lYXN0X2F0bCAsIGFyZWFfbGF0aXR1ZGVfd2VzdF9hdGwgLCBhcmVhX2xhdGl0dWRlX2Vhc3RfaW5kICwgYXJlYV9sYXRpdHVkZV93ZXN0X2luZCwgZmlsZSA9IGhlcmU6OmhlcmUoIkZpZ3VyZXMiLCJGaWd1cmUzXzUiLCAibGF0aXR1ZGVfMmRlZ3JlZV9tYXBzLlJEYXRhIikpCmBgYAoKQ29tYmluaW5nIHBsb3RzCgpyZWdpb25fbWFwczogCiJ3ZXN0X3BhY19zcGRmX3NoaWZ0IiwgCiJlYXN0X3BhY19zcGRmX3NoaWZ0IiwgCiJ3ZXN0X2F0bF9zcGRmIiwgCiJ3ZXN0X2luZF9zcGRmIiwgCiJlYXN0X2F0bF9zcGRmX25vYnVmIiwgCiJlYXN0X2luZF9zcGRmIgoKUGxvdHMgb2YgYXJlYSB2ZXJzdXMgbGF0aXR1ZGUKYXJlYV9sYXRpdHVkZV9lYXN0X3BhYwphcmVhX2xhdGl0dWRlX3dlc3RfcGFjCmFyZWFfbGF0aXR1ZGVfZWFzdF9hdGwKYXJlYV9sYXRpdHVkZV93ZXN0X2F0bAphcmVhX2xhdGl0dWRlX2Vhc3RfaW5kCmFyZWFfbGF0aXR1ZGVfd2VzdF9pbmQKCk5vdywgY29tYmluZSBwbG90cwoKYGBge3IgY29tYmluaW5nIHBsb3RzfQpsaWJyYXJ5KGVnZykKbGlicmFyeShnZ3B1YnIpCgojd2VzdCBwYWNpZmljCih3ZXN0X3BhY2lmaWNfbWVyZ2VfbWFwX3Bsb3QgPC0gZWdnOjpnZ2FycmFuZ2UocmVnaW9uX21hcHNbWzFdXSwgCiAgICAgICAgICBhcmVhX2xhdGl0dWRlX3dlc3RfcGFjIAogICAgICAgICAgKyAKICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpICksIAoKICAgICAgICAgIG5yb3cgPSAxLAogICAgICAgICAgdG9wID0gVCwKICAgICAgICAgIHdpZHRocyA9IGMoMiwxKSkpCgpnZ3NhdmUocGxvdCA9IHdlc3RfcGFjaWZpY19tZXJnZV9tYXBfcGxvdCwgZmlsZW5hbWUgPSAid2VzdF9wYWNpZmljX21lcmdlX21hcF9wbG90XzJkZWdyZWVzLmpwZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iKQoKI2Vhc3QgcGFjaWZpYwooZWFzdF9wYWNpZmljX21lcmdlX21hcF9wbG90IDwtIGVnZzo6Z2dhcnJhbmdlKHJlZ2lvbl9tYXBzW1syXV0sIAogICAgICAgICAgYXJlYV9sYXRpdHVkZV9lYXN0X3BhYyAKICAgICAgICAgICsgCiAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSApCiAgICAgICAgICAsIAoKICAgICAgICAgIG5yb3cgPSAxLAogICAgICAgICAgdG9wID0gVAogICAgICAgICAgLCAKICAgICAgICAgIHdpZHRocyA9IGMoMiwxKQogICkpCgpnZ3NhdmUocGxvdCA9IGVhc3RfcGFjaWZpY19tZXJnZV9tYXBfcGxvdCwgZmlsZW5hbWUgPSAiZWFzdF9wYWNpZmljX21lcmdlX21hcF9wbG90XzJkZWdyZWVzLmpwZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iKQoKI2JvdGggdG9nZXRoZXIKbGlicmFyeShjb3dwbG90KQpmaWd1cmVfM19wYWNpZmljX21lcmdlX3RvcCA8LSBlZ2c6OmdnYXJyYW5nZShyZWdpb25fbWFwc1tbMV1dICsgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCBwbG90Lm1hcmdpbiA9IHVuaXQoYygwLjUsMC41LDAuNSwwLjUpLCJjbSIpKSwKICAgICAgICAgIGFyZWFfbGF0aXR1ZGVfd2VzdF9wYWMgKyAKICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMC41LDAuNSwwLjUsMC41KSwiY20iKSksCiAgICAgICAgICBucm93ID0gMSwgbmNvbCA9IDIsIHRvcCA9IFQsIGJvdHRvbSA9IFQsIHdpZHRocyA9IGMoMS41LDEpKQoKZmlndXJlXzNfcGFjaWZpY19tZXJnZV9ib3R0b20gPC0gZWdnOjpnZ2FycmFuZ2UocmVnaW9uX21hcHNbWzJdXSArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAuNSwwLjUsMC41LDAuNSksImNtIikpLAogICAgICAgICAgYXJlYV9sYXRpdHVkZV9lYXN0X3BhYyArIAogICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMC41LDAuNSwwLjUsMC41KSwiY20iKSksCiAgICAgICAgICBucm93ID0gMSwgbmNvbCA9IDIsIHRvcCA9IFQsIGJvdHRvbSA9IFQsIHdpZHRocyA9IGMoMS41LDEpKQoKbGVnZW5kIDwtIGdldF9sZWdlbmQoYXJlYV9sYXRpdHVkZV9lYXN0X3BhYykKCmZpZ3VyZV8zX3BhY2lmaWNfbWVyZ2UgPC0gcGxvdF9ncmlkKGZpZ3VyZV8zX3BhY2lmaWNfbWVyZ2VfdG9wLCBmaWd1cmVfM19wYWNpZmljX21lcmdlX2JvdHRvbSwgbmNvbCA9IDEsIG5yb3cgPSAyLCBsYWJlbHMgPSBjKCJhLiIsImIuIiksIGF4aXMgPSAibCIsIGFsaWduID0gInYiLCBoanVzdCA9IC03LCByZWxfaGVpZ2h0cyA9IGMoMSwxLjUpKQoKZmlndXJlXzNfcGFjaWZpY19tZXJnZV9sZWdlbmQgPC0gcGxvdF9ncmlkKGZpZ3VyZV8zX3BhY2lmaWNfbWVyZ2UsIGxlZ2VuZCwgbmNvbCA9IDIsIG5yb3cgPSAxLCByZWxfd2lkdGhzID0gYyg0LDEpKQoKZ2dzYXZlKGZpZ3VyZV8zX3BhY2lmaWNfbWVyZ2VfbGVnZW5kLCBwYXRoID0gaGVyZTo6aGVyZSgiRmlndXJlcyIsICJGaWd1cmUzXzUiKSwgZmlsZW5hbWUgPSAiRmlndXJlM19QYWNpZmljX2xhdGl0dWRlX2FyZWEuanBnIiwgaGVpZ2h0ID0gNCwgd2lkdGggPSA2LCB1bml0ID0gImluIikKCmBgYAoKCmBgYHtyIGF0bGFudGljIG9jZWFufQojZWFzdCBhdGxhbnRpYwooZWFzdF9hdGxhbnRpY19tZXJnZV9tYXBfcGxvdCA8LSBlZ2c6OmdnYXJyYW5nZShyZWdpb25fbWFwc1tbNV1dLCAKICAgICAgICAgIGFyZWFfbGF0aXR1ZGVfZWFzdF9hdGwKICAgICAgICAgICsgCiAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSApCiAgICAgICAgICAsIAoKICAgICAgICAgIG5yb3cgPSAxLAogICAgICAgICAgdG9wID0gVCwKICAgICAgICAgIHdpZHRocyA9IGMoMiwxKSkpCgpnZ3NhdmUocGxvdCA9IGVhc3RfYXRsYW50aWNfbWVyZ2VfbWFwX3Bsb3QsIGZpbGVuYW1lID0gImVhc3RfYXRsYW50aWNfbWVyZ2VfbWFwX3Bsb3RfMmRlZ3JlZXMuanBnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIpCgojd2VzdCBhdGxhbnRpYwood2VzdF9hdGxhbnRpY19tZXJnZV9tYXBfcGxvdCA8LSBlZ2c6OmdnYXJyYW5nZShyZWdpb25fbWFwc1tbM11dLCAKICAgICAgICAgIGFyZWFfbGF0aXR1ZGVfd2VzdF9hdGwKICAgICAgICAgICsgCiAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSApCiAgICAgICAgICAsIAoKICAgICAgICAgIG5yb3cgPSAxLAogICAgICAgICAgdG9wID0gVCwgCiAgICAgICAgICB3aWR0aHMgPSBjKDIsMSkpKQoKZ2dzYXZlKHBsb3QgPSB3ZXN0X2F0bGFudGljX21lcmdlX21hcF9wbG90LCBmaWxlbmFtZSA9ICJ3ZXN0X2F0bGFudGljX21lcmdlX21hcF9wbG90XzJkZWdyZWVzLmpwZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iKQoKI2JvdGggdG9nZXRoZXIKbGlicmFyeShjb3dwbG90KQpmaWd1cmVfNF9hdGxhbnRpY19tZXJnZV90b3AgPC0gZWdnOjpnZ2FycmFuZ2UocmVnaW9uX21hcHNbWzNdXSArIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgcGxvdC5tYXJnaW4gPSB1bml0KGMoMC41LDAuNSwwLjUsMC41KSwiY20iKSksCiAgICAgICAgICBhcmVhX2xhdGl0dWRlX3dlc3RfYXRsICsgCiAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICAgICAgICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAuNSwwLjUsMC41LDAuNSksImNtIikpLAogICAgICAgICAgbnJvdyA9IDEsIG5jb2wgPSAyLCB0b3AgPSBULCBib3R0b20gPSBULCB3aWR0aHMgPSBjKDEuNSwxKSkKCmZpZ3VyZV80X2F0bGFudGljX21lcmdlX2JvdHRvbSA8LSBlZ2c6OmdnYXJyYW5nZShyZWdpb25fbWFwc1tbNV1dICsgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMC41LDAuNSwwLjUsMC41KSwiY20iKSksCiAgICAgICAgICBhcmVhX2xhdGl0dWRlX2Vhc3RfYXRsICsgCiAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgICAgICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygwLjUsMC41LDAuNSwwLjUpLCJjbSIpKSwKICAgICAgICAgIG5yb3cgPSAxLCBuY29sID0gMiwgdG9wID0gVCwgYm90dG9tID0gVCwgd2lkdGhzID0gYygxLjUsMSkpCgpsZWdlbmQgPC0gZ2V0X2xlZ2VuZChhcmVhX2xhdGl0dWRlX2Vhc3RfYXRsKQoKZmlndXJlXzRfYXRsYW50aWNfbWVyZ2UgPC0gcGxvdF9ncmlkKGZpZ3VyZV80X2F0bGFudGljX21lcmdlX3RvcCwgZmlndXJlXzRfYXRsYW50aWNfbWVyZ2VfYm90dG9tLCBuY29sID0gMSwgbnJvdyA9IDIsIGxhYmVscyA9IGMoImEuIiwiYi4iKSwgYXhpcyA9ICJsIiwgYWxpZ24gPSAidiIsIGhqdXN0ID0gLTcsIHJlbF9oZWlnaHRzID0gYygxLjEsMSkpCgpmaWd1cmVfNF9hdGxhbnRpY19tZXJnZV9sZWdlbmQgPC0gcGxvdF9ncmlkKGZpZ3VyZV80X2F0bGFudGljX21lcmdlLCBsZWdlbmQsIG5jb2wgPSAyLCBucm93ID0gMSwgcmVsX3dpZHRocyA9IGMoNCwxKSkKCmdnc2F2ZShmaWd1cmVfNF9hdGxhbnRpY19tZXJnZV9sZWdlbmQsIHBhdGggPSBoZXJlOjpoZXJlKCJGaWd1cmVzIiwgIkZpZ3VyZTNfNSIpLCBmaWxlbmFtZSA9ICJGaWd1cmU0X2F0bGFudGljX2xhdGl0dWRlX2FyZWEuanBnIiwgaGVpZ2h0ID0gNCwgd2lkdGggPSA2LCB1bml0ID0gImluIikKYGBgCgpgYGB7ciBpbmRpYW4gb2NlYW59CiN3ZXN0IGluZGlhbgood2VzdF9pbmRpYW5fbWVyZ2VfbWFwX3Bsb3QgPC0gZWdnOjpnZ2FycmFuZ2UocmVnaW9uX21hcHNbWzRdXSwgCiAgICAgICAgICBhcmVhX2xhdGl0dWRlX3dlc3RfaW5kIAogICAgICAgICAgKyAKICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpICkKICAgICAgICAgICwgCgogICAgICAgICAgbnJvdyA9IDEsCiAgICAgICAgICB0b3AgPSBUKSkKCmdnc2F2ZShwbG90ID0gd2VzdF9pbmRpYW5fbWVyZ2VfbWFwX3Bsb3QsIGZpbGVuYW1lID0gIndlc3RfaW5kaWFuX21lcmdlX21hcF9wbG90XzJkZWdyZWVzLmpwZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iKQoKCiNlYXN0IGluZGlhbgooZWFzdF9pbmRpYW5fbWVyZ2VfbWFwX3Bsb3QgPC0gZWdnOjpnZ2FycmFuZ2UocmVnaW9uX21hcHNbWzZdXSwgCiAgICAgICAgICBhcmVhX2xhdGl0dWRlX2Vhc3RfaW5kCiAgICAgICAgICArIAogICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkgKQogICAgICAgICAgLCAKCiAgICAgICAgICBucm93ID0gMSwKICAgICAgICAgIHRvcCA9IFQpKQoKZ2dzYXZlKHBsb3QgPSBlYXN0X2luZGlhbl9tZXJnZV9tYXBfcGxvdCwgZmlsZW5hbWUgPSAiZWFzdF9pbmRpYW5fbWVyZ2VfbWFwX3Bsb3RfMmRlZ3JlZXMuanBnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIpCgojYm90aCB0b2dldGhlcgpsaWJyYXJ5KGNvd3Bsb3QpCmZpZ3VyZV81X2luZGlhbl9tZXJnZV90b3AgPC0gZWdnOjpnZ2FycmFuZ2UocmVnaW9uX21hcHNbWzRdXSArIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgcGxvdC5tYXJnaW4gPSB1bml0KGMoMC41LDAuNSwwLjUsMC41KSwiY20iKSksCiAgICAgICAgICBhcmVhX2xhdGl0dWRlX3dlc3RfaW5kICsgCiAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICAgICAgICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAuNSwwLjUsMC41LDAuNSksImNtIikpLAogICAgICAgICAgbnJvdyA9IDEsIG5jb2wgPSAyLCB0b3AgPSBULCBib3R0b20gPSBULCB3aWR0aHMgPSBjKDEuNSwxKSkKCmZpZ3VyZV81X2luZGlhbl9tZXJnZV9ib3R0b20gPC0gZWdnOjpnZ2FycmFuZ2UocmVnaW9uX21hcHNbWzZdXSArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAuNSwwLjUsMC41LDAuNSksImNtIikpLAogICAgICAgICAgYXJlYV9sYXRpdHVkZV9lYXN0X2luZCArIAogICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMC41LDAuNSwwLjUsMC41KSwiY20iKSksCiAgICAgICAgICBucm93ID0gMSwgbmNvbCA9IDIsIHRvcCA9IFQsIGJvdHRvbSA9IFQsIHdpZHRocyA9IGMoMS41LDEpKQoKbGVnZW5kIDwtIGdldF9sZWdlbmQoYXJlYV9sYXRpdHVkZV9lYXN0X2luZCkKCmZpZ3VyZV81X2luZGlhbl9tZXJnZSA8LSBwbG90X2dyaWQoZmlndXJlXzVfaW5kaWFuX21lcmdlX3RvcCwgZmlndXJlXzVfaW5kaWFuX21lcmdlX2JvdHRvbSwgbmNvbCA9IDEsIG5yb3cgPSAyLCBsYWJlbHMgPSBjKCJhLiIsImIuIiksIGF4aXMgPSAibCIsIGFsaWduID0gInYiLCBoanVzdCA9IC03LCByZWxfaGVpZ2h0cyA9IGMoMSwxLjIpKQoKZmlndXJlXzVfaW5kaWFuX21lcmdlX2xlZ2VuZCA8LSBwbG90X2dyaWQoZmlndXJlXzVfaW5kaWFuX21lcmdlLCBsZWdlbmQsIG5jb2wgPSAyLCBucm93ID0gMSwgcmVsX3dpZHRocyA9IGMoNCwxKSkKCmdnc2F2ZShmaWd1cmVfNV9pbmRpYW5fbWVyZ2VfbGVnZW5kLCBwYXRoID0gaGVyZTo6aGVyZSgiRmlndXJlcyIsICJGaWd1cmUzXzUiKSwgZmlsZW5hbWUgPSAiRmlndXJlNV9pbmRpYW5fbGF0aXR1ZGVfYXJlYS5qcGciLCBoZWlnaHQgPSA0LCB3aWR0aCA9IDYsIHVuaXQgPSAiaW4iKQpgYGAKQW5kIG5vdyBmaW5hbCBtZXJnZSBmb3IgZmlndXJlcyAzLTUKYGBge3IgZmluYWwgbWVyZ2UgZmlndXJlc30KaW5kaWFuX2xhdGl0dWRlXzJfcGxvdHMgPC0gZ2dhcnJhbmdlKHdlc3RfaW5kaWFuX21lcmdlX21hcF9wbG90LCBlYXN0X2luZGlhbl9tZXJnZV9tYXBfcGxvdCwgbnJvdyA9IDIsIG5jb2wgPSAxKQpnZ3NhdmUoaW5kaWFuX2xhdGl0dWRlXzJfcGxvdHMsIGZpbGUgPSAiaW5kaWFuX2xhdGl0dWRlXzJfcGxvdHMuanBnIiwgaGVpZ2h0ID0gNiwgdW5pdCA9ICJpbiIpCmdnc2F2ZShpbmRpYW5fbGF0aXR1ZGVfMl9wbG90cywgZmlsZSA9ICJpbmRpYW5fbGF0aXR1ZGVfMl9wbG90cy5wZGYiLCBoZWlnaHQgPSA2LCB1bml0ID0gImluIikKCnBhY2lmaWNfbGF0aXR1ZGVfMl9wbG90cyA8LSBnZ2FycmFuZ2Uod2VzdF9wYWNpZmljX21lcmdlX21hcF9wbG90LCBlYXN0X3BhY2lmaWNfbWVyZ2VfbWFwX3Bsb3QsIG5yb3cgPSAyLCBuY29sID0gMSkKZ2dzYXZlKHBhY2lmaWNfbGF0aXR1ZGVfMl9wbG90cywgZmlsZSA9ICJwYWNpZmljX2xhdGl0dWRlXzJfcGxvdHMuanBnIiwgaGVpZ2h0ID0gNiwgdW5pdCA9ICJpbiIpCmdnc2F2ZShwYWNpZmljX2xhdGl0dWRlXzJfcGxvdHMsIGZpbGUgPSAicGFjaWZpY19sYXRpdHVkZV8yX3Bsb3RzLnBkZiIsIGhlaWdodCA9IDYsIHVuaXQgPSAiaW4iKQoKYXRsYW50aWNfbGF0aXR1ZGVfMl9wbG90cyA8LSBnZ2FycmFuZ2Uod2VzdF9hdGxhbnRpY19tZXJnZV9tYXBfcGxvdCwgZWFzdF9hdGxhbnRpY19tZXJnZV9tYXBfcGxvdCwgbnJvdyA9IDIsIG5jb2wgPSAxKQpnZ3NhdmUoYXRsYW50aWNfbGF0aXR1ZGVfMl9wbG90cywgZmlsZSA9ICJhdGxhbnRpY19sYXRpdHVkZV8yX3Bsb3RzLmpwZyIsIGhlaWdodCA9IDYsIHVuaXQgPSAiaW4iKQpnZ3NhdmUoYXRsYW50aWNfbGF0aXR1ZGVfMl9wbG90cywgZmlsZSA9ICJhdGxhbnRpY19sYXRpdHVkZV8yX3Bsb3RzLnBkZiIsIGhlaWdodCA9IDYsIHVuaXQgPSAiaW4iKQpgYGAKCgpTdW1tYXJ5IFRhYmxlIG9mIFNoaWZ0cyBhd2F5IGZyb20gRXF1YXRvcgoKCmBgYHtyIHN0YXRpc3RpY3MgdGFibGV9CnJlZ2lvbmFsX3N0YXRpc3RpY3MgPC0gZGF0YS50YWJsZSgpCnJlZ2lvbmFsX3N0YXRpc3RpY3NbLHJlZ2lvbiA6PSByZXAoYygiV2VzdCBQYWNpZmljIiwgIkVhc3QgUGFjaWZpYyIsICJXZXN0IEF0bGFudGljIiwgIldlc3QgSW5kaWFuIiwgIkVhc3QgQXRsYW50aWMiLCAiRWFzdCBJbmRpYW4iKSxlYWNoID0gMildWyxoZW1pc3BoZXJlIDo9IHJlcChjKCJOb3J0aGVybiIsICJTb3V0aGVybiIpLDYpXVssY29udHJhY3Rpb25zIDo9IGFzLm51bWVyaWMoTkEpXVssZXhwYW5zaW9ucyA6PSBhcy5udW1lcmljKE5BKV1bLGNvZWYgOj0gYXMubnVtZXJpYyhOQSldWyxwdmFsdWUgOj0gYXMubnVtZXJpYyhOQSldCgpzaGVsZl9hcmVhcyA8LSBjKCJ3ZXN0X3BhY19zaGVsZl9hcmVhcyIsICJlYXN0X3BhY19zaGVsZl9hcmVhcyIsICJ3ZXN0X2F0bF9zaGVsZl9hcmVhcyIsICJ3ZXN0X2luZF9zaGVsZl9hcmVhcyIsICJlYXN0X2F0bF9zaGVsZl9hcmVhcyIsICJlYXN0X2luZF9zaGVsZl9hcmVhcyIpCgpub3J0aF9tb2RzIDwtIGMoIndlc3RfcGFjX25vcnRoX21vZCIsICJlYXN0X3BhY19ub3J0aF9tb2QiLCAid2VzdF9hdGxfbm9ydGhfbW9kIiwgIndlc3RfaW5kX25vcnRoX21vZCIsICJlYXN0X2F0bF9ub3J0aF9tb2QiLCAiZWFzdF9pbmRfbm9ydGhfbW9kIikKCnNvdXRoX21vZHMgPC0gYygid2VzdF9wYWNfc291dGhfbW9kIiwgImVhc3RfcGFjX3NvdXRoX21vZCIsICJ3ZXN0X2F0bF9zb3V0aF9tb2QiLCAid2VzdF9pbmRfc291dGhfbW9kIiwgImVhc3RfYXRsX3NvdXRoX21vZCIsICJlYXN0X2luZF9zb3V0aF9tb2QiKQoKZm9yIChpIGluIDE6bGVuZ3RoKHNoZWxmX2FyZWFzKSkgewoKICB0aGlzX3NoZWxmX2FyZWEgPC0gZ2V0KHNoZWxmX2FyZWFzW2ldKQogICAgI3BvcHVsYXRlIHdlc3QgcGFjaWZpYwogICAgcmVnaW9uYWxfc3RhdGlzdGljc1tyZWdpb24gPT0gdW5pcXVlKHJlZ2lvbmFsX3N0YXRpc3RpY3NbLHJlZ2lvbl0pW2ldICYgaGVtaXNwaGVyZSA9PSAiTm9ydGhlcm4iLCAiY29udHJhY3Rpb25zIl0gPC0gcm91bmQodGhpc19zaGVsZl9hcmVhW2xhdGl0dWRlX2VuZCA+IDAgJiBjaGFuZ2VfYWJvdmVfMmZvbGQgPT0gLTEsLk5dL25yb3codGhpc19zaGVsZl9hcmVhW2xhdGl0dWRlX2VuZCA+IDAgJiAhaXMubmEocGVyY2VudF9jaGFuZ2UpXSksNCkqMTAwICNub3J0aGVybiBoZW1pc3BoZXJlIGNvbnRyYWN0aW9uCiAgICAKICAgIHJlZ2lvbmFsX3N0YXRpc3RpY3NbcmVnaW9uID09IHVuaXF1ZShyZWdpb25hbF9zdGF0aXN0aWNzWyxyZWdpb25dKVtpXSAmIGhlbWlzcGhlcmUgPT0gIlNvdXRoZXJuIiwgImNvbnRyYWN0aW9ucyJdIDwtIHJvdW5kKHRoaXNfc2hlbGZfYXJlYVtsYXRpdHVkZV9lbmQgPCAwICYgY2hhbmdlX2Fib3ZlXzJmb2xkID09IC0xLC5OXS9ucm93KHRoaXNfc2hlbGZfYXJlYVtsYXRpdHVkZV9lbmQgPCAwICYgIWlzLm5hKHBlcmNlbnRfY2hhbmdlKV0pLDQpKjEwMCAjc291dGhlcm4gaGVtaXNwaGVyZSBjb250cmFjdGlvbgogICAgCiAgICByZWdpb25hbF9zdGF0aXN0aWNzW3JlZ2lvbiA9PSB1bmlxdWUocmVnaW9uYWxfc3RhdGlzdGljc1sscmVnaW9uXSlbaV0gJiBoZW1pc3BoZXJlID09ICJOb3J0aGVybiIsICJleHBhbnNpb25zIl0gPC0gcm91bmQodGhpc19zaGVsZl9hcmVhW2xhdGl0dWRlX2VuZCA+IDAgJiBjaGFuZ2VfYWJvdmVfMmZvbGQgPT0gMSwuTl0vbnJvdyh0aGlzX3NoZWxmX2FyZWFbbGF0aXR1ZGVfZW5kID4gMCAmICFpcy5uYShwZXJjZW50X2NoYW5nZSldKSw0KSoxMDAgI25vcnRoZXJuIGhlbWlzcGhlcmUgZXhwYW5zaW9uCiAgICAKICAgIHJlZ2lvbmFsX3N0YXRpc3RpY3NbcmVnaW9uID09IHVuaXF1ZShyZWdpb25hbF9zdGF0aXN0aWNzWyxyZWdpb25dKVtpXSAmIGhlbWlzcGhlcmUgPT0gIlNvdXRoZXJuIiwgImV4cGFuc2lvbnMiXSA8LSByb3VuZCh0aGlzX3NoZWxmX2FyZWFbbGF0aXR1ZGVfZW5kIDwgMCAmIGNoYW5nZV9hYm92ZV8yZm9sZCA9PSAxLC5OXS9ucm93KHRoaXNfc2hlbGZfYXJlYVtsYXRpdHVkZV9lbmQgPCAwICYgIWlzLm5hKHBlcmNlbnRfY2hhbmdlKV0pLDQpKjEwMCAjc291dGhlcm4gaGVtaXNwaGVyZSBleHBhbnNpb24KICAgIAogICAgI25vcnRoZXJuIG1vZAogICAgcmVnaW9uYWxfc3RhdGlzdGljc1tyZWdpb24gPT0gdW5pcXVlKHJlZ2lvbmFsX3N0YXRpc3RpY3NbLHJlZ2lvbl0pW2ldICYgaGVtaXNwaGVyZSA9PSAiTm9ydGhlcm4iLCAiY29lZiJdIDwtIHJvdW5kKGdldChub3J0aF9tb2RzW2ldKSRjb2VmZmljaWVudHNbMl0sMikKICAgIHJlZ2lvbmFsX3N0YXRpc3RpY3NbcmVnaW9uID09IHVuaXF1ZShyZWdpb25hbF9zdGF0aXN0aWNzWyxyZWdpb25dKVtpXSAmIGhlbWlzcGhlcmUgPT0gIk5vcnRoZXJuIiwgInB2YWx1ZSJdIDwtIHJvdW5kKHN1bW1hcnkoZ2V0KG5vcnRoX21vZHNbaV0pKSRjb2VmZmljaWVudHNbLCJQcig+fHR8KSJdWzJdLDIpCiAgICAKICAgICNzb3V0aGVybiBtb2QKICAgIHJlZ2lvbmFsX3N0YXRpc3RpY3NbcmVnaW9uID09IHVuaXF1ZShyZWdpb25hbF9zdGF0aXN0aWNzWyxyZWdpb25dKVtpXSAmIGhlbWlzcGhlcmUgPT0gIlNvdXRoZXJuIiwgImNvZWYiXSA8LSByb3VuZChnZXQoc291dGhfbW9kc1tpXSkkY29lZmZpY2llbnRzWzJdLDIpCiAgICByZWdpb25hbF9zdGF0aXN0aWNzW3JlZ2lvbiA9PSB1bmlxdWUocmVnaW9uYWxfc3RhdGlzdGljc1sscmVnaW9uXSlbaV0gJiBoZW1pc3BoZXJlID09ICJTb3V0aGVybiIsICJwdmFsdWUiXSA8LSByb3VuZChzdW1tYXJ5KGdldChzb3V0aF9tb2RzW2ldKSkkY29lZmZpY2llbnRzWywiUHIoPnx0fCkiXVsyXSwyKQoKfQoKdmlldyhyZWdpb25hbF9zdGF0aXN0aWNzKQoKI3NhdmUKZndyaXRlKHJlZ2lvbmFsX3N0YXRpc3RpY3MsIGZpbGUgPSAiVGFibGUxX3JlZ2lvbmFsX3N0YXRzLmNzdiIpCmBgYAoKCmBgYHtyfQoKc2F2ZShzaWduaWZpY2FudF9jaGFuZ2VzLmxvbmcsIHNpZ25pZmljYW50X2NoYW5nZXMsIGZpbGUgPSAic2lnbmlmaWNhbnRfY2hhbmdlc18yZGVncmVlcy5SZGF0YSIpCgpgYGAKCg==